Memory (AgentMemory)

AgentMemory is an agent's long-term memory. It turns an agent's conversations into short structured memories (a decision, a learning, a pattern, a preference or a fact), lets the agent search and correct them, and writes the most useful ones into the MEMORY.md file the agent reads at the start of every session.

These endpoints are the same six methods the @opvs-ai/agentmemory skill gives an agent, plus the one that registers a conversation source. Base path: /api/v1/memory.

The four reads that find the lessons near a piece of code are further down, under Lessons near the code.

Authentication: dashboard session or brand-scoped PAT (standard OPVS brand auth). See Authentication. Reads need the memory:read scope and writes need memory:write. Everything you read or write is scoped to the brand your token is pinned to: another brand's memories are invisible to you, and a memory id from another brand answers 404, the same as one that does not exist.

The search and recall methods answer YAML by default, which costs an agent far fewer tokens. Pass format=json for JSON, or format=md for Markdown. See Format negotiation.

How a memory reaches an agent

  • From conversations. Every 10 minutes the service picks up conversations that have not been turned into memories yet. A conversation whose model call fails is retried with growing waits (10 minutes, 30 minutes, 2 hours, 8 hours) and is marked failed after the fifth attempt, so a failure is never recorded as "nothing to remember".
  • From your own calls. POST /memories stores a memory you write yourself.
  • Into the agent's workspace. Once an hour the highest-confidence active memories are written into a marked section of the MEMORY.md in the workspace the agent actually reads. Only that section is replaced: the agent's own notes in the file are never overwritten. A correction you make with PATCH shows up in search and recall at once, and in MEMORY.md at the next hourly export.

POST /api/v1/memory/agents/{agent_id}/context

Search an agent's active memories by text. The skill method is searchMemories. Returns active memories with confidence 0.3 or higher, ranked by how well they match query when you pass one. A memory not verified for more than 30 days carries stale: true and a stale_caveat.

Parameter In Type Default Notes
agent_id path string none The agent's workspace id, such as acme-sdr-001.
query query string none Words to match in the title and body. Omit it to list the agent's top memories.
kinds query string all Comma-separated: decision, learning, pattern, preference, fact, summary.
limit query integer 10 1 to 50.
format query string yaml json, yaml or md.
curl -s -X POST "https://api.opvs.ai/api/v1/memory/agents/acme-sdr-001/context?query=pricing+page&kinds=decision,fact&limit=5&format=json" \
  -H "Authorization: Bearer $OPVS_PAT"
# → 200 {"memories": […], "count": 1, "agent_id": "acme-sdr-001"}
# → 422 if limit is above 50
{
  "memories": [
    {
      "kind": "decision",
      "title": "Quote annual prices first on the pricing page",
      "body": "Prospects compared our monthly price with competitors' annual price. Show annual first.",
      "description": "Annual price first on the pricing page",
      "confidence": 0.82,
      "tags": ["pricing", "website"]
    }
  ],
  "count": 1,
  "agent_id": "acme-sdr-001"
}

Errors

Error When Resolution
401 The PAT is malformed, expired or revoked. Request a new token.
403 The token lacks memory:read. Request a token with the scope.
422 limit is outside 1 to 50. Send a value in range.
502 / 504 The memory service is unreachable, or did not answer within 30 seconds. Retry with backoff.

POST /api/v1/memory/agents/{agent_id}/context/relevant

Recall the memories most relevant to a topic or question. The skill method is recallRelevant. A text search first collects up to 100 candidates, then a language model reranks them and keeps the best limit. If the reranker fails, you get the text search order instead of an error.

Parameter In Type Default Notes
agent_id path string none The agent's workspace id.
query query string required The topic, question or conversation context, in plain language.
kinds query string all Comma-separated kinds, as above.
limit query integer 20 1 to 50.
format query string yaml json, yaml or md.
curl -s -X POST "https://api.opvs.ai/api/v1/memory/agents/acme-sdr-001/context/relevant?query=how+do+we+price+for+agencies&limit=3&format=json" \
  -H "Authorization: Bearer $OPVS_PAT"
# → 200 {"memories": […], "count": 3, "agent_id": "acme-sdr-001"}
# → 422 if query is missing

The response has the same shape as the search above. No match is not an error: it answers {"memories": [], "count": 0, "agent_id": "…"}.

Errors

Error When Resolution
401 The PAT is malformed, expired or revoked. Request a new token.
403 The token lacks memory:read. Request a token with the scope.
422 query is missing, or limit is outside 1 to 50. Send a query and a limit in range.
502 / 504 The memory service is unreachable, or did not answer within 30 seconds. Retry with backoff.

POST /api/v1/memory/memories

Store a memory you write yourself. The skill method is createMemory. It always creates a new memory: sending the same memory twice stores it twice. To change one, use PATCH.

Field Type Required Notes
agent_id string yes The agent's workspace id: 1 to 255 letters, digits, _ or -.
kind string yes decision, learning, pattern, preference or fact.
title string yes Up to 500 characters. Keep it short: it is what search shows first.
body string yes The memory itself.
description string no A one-line summary, up to 200 characters, shown beside the title in recall.
tags string[] no Tags for grouping. Three learnings sharing a tag are consolidated into a pattern.
confidence number no 0.0 to 1.0, default 0.8. It decays about 2% a week.
importance string no low, normal (default), high or critical. A critical memory does not decay.
curl -s -X POST "https://api.opvs.ai/api/v1/memory/memories" \
  -H "Authorization: Bearer $OPVS_PAT" \
  -H "Content-Type: application/json" \
  -d '{
        "agent_id": "acme-sdr-001",
        "kind": "decision",
        "title": "Quote annual prices first on the pricing page",
        "body": "Prospects compared our monthly price with competitors annual price. Show annual first.",
        "description": "Annual price first on the pricing page",
        "tags": ["pricing", "website"],
        "importance": "high"
      }'
# → 201 {"id": "9b2f6a0e-4c1d-4e8a-9d3b-2f7c1a5e8b40", "status": "active", …}
# → 403 if agent_id belongs to another brand

The response is the full memory, with its id. Keep the id to correct or delete it later.

Errors

Error When Resolution
401 The PAT is malformed, expired or revoked. Request a new token.
403 The token lacks memory:write, or agent_id is an agent another brand owns. Name one of your own agents. The answer is the same whichever brand owns it.
422 A required field is missing, confidence is outside 0 to 1, description is over 200 characters, or agent_id is not a plain workspace id (it has a ., /, a space or another character outside the set). Fix the field the error names.
502 / 504 The memory service is unreachable, or did not answer within 30 seconds. Retry with backoff.

GET /api/v1/memory/memories/stats

Counts for your brand's memories. The skill method is getStats.

Parameter In Type Default Notes
agent_id query string all agents Limit the counts to one agent.
format query string json json, yaml or md.
curl -s "https://api.opvs.ai/api/v1/memory/memories/stats?agent_id=acme-sdr-001" \
  -H "Authorization: Bearer $OPVS_PAT"
# → 200 {"total_active": 31, "total_archived": 4, "total_merged": 2, "by_kind": {…}, "avg_confidence": 0.71}
# → 401 if the token is revoked
{
  "total_active": 31,
  "total_archived": 4,
  "total_merged": 2,
  "by_kind": { "decision": 6, "learning": 14, "fact": 11 },
  "avg_confidence": 0.71
}

Errors

Error When Resolution
401 The PAT is malformed, expired or revoked. Request a new token.
403 The token lacks memory:read. Request a token with the scope.
502 / 504 The memory service is unreachable, or did not answer within 30 seconds. Retry with backoff.

PATCH /api/v1/memory/memories/{memory_id}

Correct a memory in place. The skill method is updateMemory. Only the fields you send change. Correcting beats writing a second memory that contradicts the first.

Field Type Notes
title string Replacement title.
body string Replacement body.
description string Replacement one-line summary, up to 200 characters. Recall shows it beside the title, so when you correct the body, correct this too.
kind string Re-classify the memory.
tags string[] Replaces the whole tag list.
confidence number 0.0 to 1.0.
importance string low, normal, high or critical.
status string archived retires a memory from search and recall without deleting it; active restores it.
curl -s -X PATCH "https://api.opvs.ai/api/v1/memory/memories/9b2f6a0e-4c1d-4e8a-9d3b-2f7c1a5e8b40" \
  -H "Authorization: Bearer $OPVS_PAT" \
  -H "Content-Type: application/json" \
  -d '{
        "body": "Agencies compare annual prices. Show annual first for every plan.",
        "description": "Annual price first for every plan"
      }'
# → 200 {"id": "9b2f6a0e-4c1d-4e8a-9d3b-2f7c1a5e8b40", "description": "Annual price first for every plan", …}
# → 404 if the memory is not in your brand

The response is the full memory after the change.

Errors

Error When Resolution
401 The PAT is malformed, expired or revoked. Request a new token.
403 The token lacks memory:write. Request a token with the scope.
404 No memory with that id in your brand. "Not yours" and "not there" answer the same. Check the id with a search.
422 memory_id is not a UUID, confidence is outside 0 to 1, or description is over 200 characters. Fix the value the error names.
502 / 504 The memory service is unreachable, or did not answer within 30 seconds. Retry with backoff.

DELETE /api/v1/memory/memories/{memory_id}

Delete a memory that is wrong. The skill method is deleteMemory. It stops appearing in search and recall at once, and leaves MEMORY.md at the next hourly export. For a memory that is outdated rather than wrong, PATCH it to status: archived instead.

curl -s -o /dev/null -w "%{http_code}\n" -X DELETE \
  "https://api.opvs.ai/api/v1/memory/memories/9b2f6a0e-4c1d-4e8a-9d3b-2f7c1a5e8b40" \
  -H "Authorization: Bearer $OPVS_PAT"
# → 204 (no body)
# → 404 if the memory is not in your brand, or was already deleted

Errors

Error When Resolution
401 The PAT is malformed, expired or revoked. Request a new token.
403 The token lacks memory:write. Request a token with the scope.
404 No memory with that id in your brand, or it is already deleted. Nothing to do if you deleted it before.
422 memory_id is not a UUID. Send the memory's id.
502 / 504 The memory service is unreachable, or did not answer within 30 seconds. Retry with backoff.

POST /api/v1/memory/sources

Register a conversation source for one of your agents, so the service turns that agent's conversations into memories. A source can only name an agent your brand owns.

Field Type Required Notes
agent_id string yes Your agent's workspace id: 1 to 255 letters, digits, _ or -.
source_type string yes openclaw (agent chat sessions), agentboard (completed tasks) or claude_code.
config object no Source-specific settings.
enabled boolean no Default true.
curl -s -X POST "https://api.opvs.ai/api/v1/memory/sources" \
  -H "Authorization: Bearer $OPVS_PAT" \
  -H "Content-Type: application/json" \
  -d '{"agent_id": "acme-sdr-001", "source_type": "openclaw"}'
# → 201 {"id": "3c5e9d12-7a4b-4f60-8e21-6b9d0c4f2a17", "agent_id": "acme-sdr-001", …}
# → 403 if the agent is not your brand's

Errors

Error When Resolution
401 The PAT is malformed, expired or revoked. Request a new token.
403 The token lacks memory:write; or agent_id is not an agent your brand owns (another brand's, or one of the platform's own agents); or your plan's source limit is reached (the body then says quota_exceeded). Name one of your own agents, or upgrade the plan. The ownership answer is the same for every agent that is not yours, so it does not reveal whether that agent exists.
422 agent_id is not a plain workspace id, or a required field is missing. Fix the field the error names.
503 Ownership could not be checked just now. Nothing was created. Retry shortly.
502 / 504 The memory service is unreachable, or did not answer within 30 seconds. Retry with backoff.

Lessons near the code

A lesson is a short typed entry (a rule, a decision, a gotcha) that is anchored to code: a file, a folder, or one function or class inside a file. When an agent is about to change some code, it should read the lessons on that code and on the code around it, not the whole rulebook. These four reads do that. They need a project with a code repository attached and indexed; see Code index.

Read Answers
POST /entries:near "Which lessons apply to these files, and to the code they import, call or sit next to?"
GET /entries/search?anchor= "Which lessons are on this file, on its functions, or on its folders?"
POST /anchors:lookup "How many lessons sit on each of these code nodes, and which are the top few?"
POST /entries:similar "Is there already a lesson that says this?"

These routes answer JSON only; they do not take the format parameter. Every read is scoped to your brand: another brand's project answers 404 on entries:near, the same as one that does not exist, and another brand's lessons never appear in any answer.

A lesson follows its code when the file is renamed or moved. The code index notices the move on the next index of the repository, and the lesson's anchor is moved to the new path. From then on the lesson answers at the new path in all four reads, with no change on your side.

A lesson goes stale when its code is deleted. When the next index finds that the file, function or class a lesson is anchored on was removed, the lesson is marked stale: true, with stale_reason set to code removed in <commit>. It is not deleted: it still answers in entries/search?anchor=, and GET /entries/search?stale=true lists every stale lesson, so you can review it and retract or re-anchor it. A folder anchor does not keep a lesson alive: a lesson anchored on src/billing/invoice.py and on src/billing/ goes stale when the file is deleted, even though the folder is still there. A lesson anchored only on folders goes stale when all of those folders are removed.

POST /api/v1/memory/entries:near

Walk the code graph outward from the files or nodes you name, then return the live lessons found on every node the walk reached. The skill method is entriesNear. Needs the memory:read and code:read scopes.

Field Type Default Notes
project_id UUID required A project of your brand with an attached repository.
paths string[] [] Files to start from, written as repository paths (src/billing/invoice.py) or anchors (src/billing/invoice.py#Invoice.total). The service resolves them. A path that does not resolve to live code is skipped.
node_ids UUID[] [] Stable code-node ids to start from, when you already hold them (for example from nodes/resolve). paths plus node_ids must total 1 to 50.
depth integer 2 Hops to walk, 0 to 3. 0 reads only the start nodes.
kinds string[] ["import", "contains"] Edges to follow. import: file imports and imports of a named function or class. call: a function calling a function. contains: a file's folder and a folder's files, and a symbol's file. With contains, each hop can climb one folder level.
direction string both out follows what a node imports, calls or contains. in follows what imports or calls it, and its parent. both follows both.
hub_cap integer 25 1 to 200. A node reached during the walk that has more edges than this of one kind is a hub: it is listed in damped and the walk does not continue past it. Counting per kind means a file with many imports but few calls is damped only for imports. A start node is never a hub: the walk always takes every neighbour of the files you name, however many edges they have.
limit integer 20 1 to 100. Most lessons returned.
import os
import httpx

resp = httpx.post(
    "https://api.opvs.ai/api/v1/memory/entries:near",
    headers={"Authorization": f"Bearer {os.environ['OPVS_PAT']}"},
    json={
        "project_id": "2f6b1c9e-8d4a-4e2b-9c71-5a0d3e8f6b12",
        "paths": ["src/billing/invoice.py"],
        "kinds": ["import", "call", "contains"],
        "limit": 10,
    },
    timeout=60,
)
resp.raise_for_status()  # → 404 if the project is not your brand's, 422 for 0 or more than 50 start points
for lesson in resp.json()["entries"]:
    print(lesson["hops"], lesson["path"])  # → 1 lessons/billing/round-half-even.md
curl -s -X POST "https://api.opvs.ai/api/v1/memory/entries:near" \
  -H "Authorization: Bearer $OPVS_PAT" \
  -H "Content-Type: application/json" \
  -d '{"project_id": "2f6b1c9e-8d4a-4e2b-9c71-5a0d3e8f6b12", "paths": ["src/billing/invoice.py"], "limit": 10}'
# → 200 {"entries": […], "reached_nodes": 14, "damped": […], "truncated": false, "degraded": null}
{
  "entries": [
    {
      "id": "billing/round-half-even",
      "path": "lessons/billing/round-half-even.md",
      "type": "rule",
      "body": "Round invoice totals half-even, never half-up: the tax authority audits the rounding mode.",
      "pinned": false,
      "stale": false,
      "stale_reason": null,
      "hops": 1,
      "via_node_id": "7a1d0c3e-5b9f-4d26-8e40-2c6f1b8a9d73",
      "path_to": [
        {"node_id": "c4e8a2f1-9b3d-4a57-b6e0-1f2d3c4b5a69", "path": "src/billing/invoice.py", "edge": null},
        {"node_id": "7a1d0c3e-5b9f-4d26-8e40-2c6f1b8a9d73", "path": "src/billing/money.py", "edge": "import"}
      ]
    }
  ],
  "reached_nodes": 14,
  "damped": [
    {"node_id": "0b9e4d2c-6a1f-4c38-9e57-3d8a2b1c0f46", "path": "src/core/settings.py", "degree": 212}
  ],
  "truncated": false,
  "degraded": null
}
Response field Meaning
entries[] Live lessons, each listed once at the nearest node that carries it. Pinned lessons first, then fewer hops.
entries[].hops 0: the lesson is on a start node or anywhere under it. 1 or more: on a node the walk reached.
entries[].via_node_id, path_to The node the lesson was found on, and the chain of nodes from a start node to it. Each step's edge is the edge kind that reached it (import, symbol_import, call or contains); the first step's is null.
reached_nodes How many code nodes the walk reached, start nodes included. 0 means none of your start points is live code.
damped[] Hubs the walk stopped at, with their edge count of the kind that made them a hub.
truncated true when more lessons matched than limit, or the walk reached its cap of 1,000 nodes.
degraded null, or why the answer is empty or partial: no_ready_index, code_index_unavailable or memory_unavailable. A degraded answer is still 200.

A folder that the walk reaches contributes only the lessons anchored on that folder itself, not every lesson under it; a start node contributes everything under it.

How many nodes "near" is, measured. On a production repository (2026-10-11), with the defaults (import and contains, hub_cap 25):

Start file Depth 1: nodes / lessons Depth 2: nodes / lessons
A hub, imported by 139 files 149 / 7 937 / 7
A mid-sized file 76 / 3 109 / 3
A leaf file 40 / 3 45 / 3

So the default answer is a handful of nearby lessons, not the whole repository. The node count grows fast once a walk passes a hub: with hub_cap 200, the mid-sized file's depth-2 walk reached 719 nodes (7 lessons) instead of 109, and the hub's reached the 1,000-node cap (truncated: true). Raise hub_cap only when you want the walk to continue through the hubs it meets along the way.

Errors

Error When Resolution
401 The PAT is malformed, expired or revoked. Request a new token.
403 The token lacks memory:read or code:read. Request a token with both scopes.
404 The project does not exist, belongs to another brand, or has no repository attached. Check project_id; attach a repository to the project first.
422 paths plus node_ids is 0 or more than 50; a field is out of range or unknown; or a path is not a valid anchor. Fix the field the error names.
200 with degraded The project has no ready index yet (no_ready_index), or the code index or the memory service could not be read. Retry later; for no_ready_index, wait for the first index of the repository.

GET /api/v1/memory/entries/search?anchor=

Return the lessons on one file and around it: anchored on the file itself, on a function or class inside it, or on one of its folders up to the repository root. The skill method is entryContext. Needs memory:read.

Parameter Type Default Notes
anchor string required here A repository path such as src/billing/invoice.py, or one symbol in it (src/billing/invoice.py#Invoice.total).
project_id UUID none Limit folder and function matches to one project. Recommended.
q string none Words to match within those lessons.
type string all One lesson type, such as rule.
scope string all One scope tag.
limit integer 20 1 to 500.
import os
import httpx

resp = httpx.get(
    "https://api.opvs.ai/api/v1/memory/entries/search",
    headers={"Authorization": f"Bearer {os.environ['OPVS_PAT']}"},
    params={
        "anchor": "src/billing/invoice.py",
        "project_id": "2f6b1c9e-8d4a-4e2b-9c71-5a0d3e8f6b12",
        "limit": 10,
    },
)
resp.raise_for_status()  # → 403 if the token lacks memory:read
for item in resp.json()["items"]:
    print(item["matched_by"], item["path"])  # → anchor lessons/billing/invoice-immutable.md
{
  "query": "",
  "total": 3,
  "items": [
    {"id": "billing/invoice-immutable", "path": "lessons/billing/invoice-immutable.md", "type": "rule", "matched_by": "anchor", "pinned": true, "anchors": ["src/billing/invoice.py"]},
    {"id": "billing/total-includes-tax", "path": "lessons/billing/total-includes-tax.md", "type": "gotcha", "matched_by": "symbol", "pinned": false, "anchors": ["src/billing/invoice.py#Invoice.total"]},
    {"id": "billing/no-floats", "path": "lessons/billing/no-floats.md", "type": "rule", "matched_by": "folder", "pinned": false, "anchors": ["src/billing/"]}
  ],
  "warnings": []
}

Each item carries the full lesson (body, author, card, anchors and so on; abridged above) and matched_by: anchor (on the file itself), symbol (on a function or class in the file) or folder (on one of its folders). Pinned lessons come first, then anchor, then symbol, then folder with the nearest folder first.

Errors

Error When Resolution
401 The PAT is malformed, expired or revoked. Request a new token.
403 The token lacks memory:read. Request a token with the scope.
422 limit is outside 1 to 500, or project_id is not a UUID. Send a value in range.
502 / 504 The memory service is unreachable, or did not answer in time. Retry with backoff.

POST /api/v1/memory/anchors:lookup

Count the live lessons on each of up to 1,000 code nodes, and return the top five for each node. The dashboard's Code view uses it to show how many lessons sit on each folder and file. The skill method is anchorsLookup. Needs memory:read.

Field Type Default Notes
project_id UUID required The project the node ids belong to.
node_ids UUID[] required Up to 1,000 stable code-node ids.
match string subtree subtree counts lessons on the node or anywhere under it. exact counts only lessons on the node itself.
import os
import httpx

resp = httpx.post(
    "https://api.opvs.ai/api/v1/memory/anchors:lookup",
    headers={"Authorization": f"Bearer {os.environ['OPVS_PAT']}"},
    json={
        "project_id": "2f6b1c9e-8d4a-4e2b-9c71-5a0d3e8f6b12",
        "node_ids": ["c4e8a2f1-9b3d-4a57-b6e0-1f2d3c4b5a69"],
        "match": "exact",
    },
)
resp.raise_for_status()  # → 422 if node_ids holds more than 1,000 ids
print(resp.json()["counts"])  # → {"c4e8a2f1-9b3d-4a57-b6e0-1f2d3c4b5a69": 2}
{
  "counts": {"c4e8a2f1-9b3d-4a57-b6e0-1f2d3c4b5a69": 2},
  "entries": {
    "c4e8a2f1-9b3d-4a57-b6e0-1f2d3c4b5a69": [
      {"id": "billing/invoice-immutable", "path": "lessons/billing/invoice-immutable.md", "type": "rule", "body": "Never edit an issued invoice; issue a credit note.", "pinned": true, "stale": false, "stale_reason": null}
    ]
  }
}

counts lists only nodes with at least one lesson; a node with none is absent, not 0. entries holds at most five lessons per node, pinned first, then newest. Retired and superseded lessons are never counted.

Errors

Error When Resolution
401 The PAT is malformed, expired or revoked. Request a new token.
403 The token lacks memory:read. Request a token with the scope.
422 More than 1,000 node_ids, an id that is not a UUID, or match is not subtree or exact. Split the request into pages of 1,000.
502 / 504 The memory service is unreachable, or did not answer in time. Retry with backoff.

POST /api/v1/memory/entries:similar

Compare a piece of text with your brand's live lessons by meaning, and return the closest ones. Use it before writing a lesson, to avoid a second copy of one that already exists. It writes nothing. The skill method is entriesSimilar. Needs memory:read.

Field Type Default Notes
text string required The lesson you are about to write, or its gist.
type string all Compare only with lessons of this type.
k integer 3 1 to 10. Most matches returned.
threshold number 0.90 -1 to 1. Lowest cosine similarity that counts as a match. Lower it to see looser matches.
import os
import httpx

resp = httpx.post(
    "https://api.opvs.ai/api/v1/memory/entries:similar",
    headers={"Authorization": f"Bearer {os.environ['OPVS_PAT']}"},
    json={"text": "Round invoice totals half-even, not half-up", "k": 3, "threshold": 0.8},
)
resp.raise_for_status()  # → 422 if text is empty or k is above 10
for match in resp.json()["matches"]:
    print(match["similarity"], match["path"])  # → 0.946213 lessons/billing/round-half-even.md
{
  "matches": [
    {"id": "billing/round-half-even", "path": "lessons/billing/round-half-even.md", "similarity": 0.946213, "type": "rule", "pinned": false}
  ],
  "compared": 412,
  "without_embedding": 3
}

compared is how many lessons were compared. A new lesson is compared once its embedding has been computed in the background; until then it is counted in without_embedding. If the embedding service is down, the answer is 200 with no matches and a degraded reason, never an error.

Errors

Error When Resolution
401 The PAT is malformed, expired or revoked. Request a new token.
403 The token lacks memory:read. Request a token with the scope.
422 text is empty, k is outside 1 to 10, or threshold is outside -1 to 1. Fix the field the error names.
502 / 504 The memory service is unreachable, or did not answer in time. Retry with backoff.

Duplicate warnings on writes

Lessons written in a batch are checked the same way. When a repository's knowledge files are synced into lessons, each written lesson in the response can carry possible_duplicate_of: up to three existing lessons at 0.90 similarity or above, each with its id, path and similarity. The check never blocks a write. It covers up to 200 lessons per write and fully compares the first 25; when a write holds more, the response says "duplicate_check": "truncated" and the lessons past that point carry no possible_duplicate_of. Check those with entries:similar.

Powered by OPVS
Memory (AgentMemory) | OPVS