@yugabytedb/meko-mcp 2.2.0 → 2.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. package/README.md +106 -38
  2. package/assets/hooks-handlers/lib/capture-cleanup-cli.js +1473 -0
  3. package/assets/hooks-handlers/lib/capture-notices.js +131 -14
  4. package/assets/hooks-handlers/lib/capture-state.js +95 -1
  5. package/assets/hooks-handlers/lib/capture-status-cli.js +6 -2
  6. package/assets/hooks-handlers/lib/capture.js +1237 -137
  7. package/assets/hooks-handlers/lib/checkpoint-timer.js +51 -10
  8. package/assets/hooks-handlers/lib/journal-bridge.js +218 -0
  9. package/assets/hooks-handlers/lib/kiro-handler.js +26 -4
  10. package/assets/hooks-handlers/lib/opencode-handler.js +620 -0
  11. package/assets/hooks-handlers/lib/opencode-normalizer.js +145 -0
  12. package/assets/hooks-handlers/lib/terminal-handoff.js +10 -1
  13. package/assets/opencode-plugin/meko.js +213 -0
  14. package/assets/scripts/meko-statusline.sh +85 -18
  15. package/assets/skills/meko-mcp-tools/SKILL.md +57 -14
  16. package/assets/skills/meko-mcp-tools/references/_sections.md +2 -2
  17. package/assets/skills/meko-mcp-tools/references/tools-agent-id-conventions.md +15 -7
  18. package/assets/skills/meko-mcp-tools/references/tools-cookbook.md +86 -14
  19. package/assets/skills/meko-mcp-tools/references/tools-datapack-workflow.md +1 -1
  20. package/assets/skills/meko-mcp-tools/references/tools-known-limitations.md +29 -6
  21. package/assets/skills/meko-mcp-tools/references/tools-memory-vs-conversation.md +8 -4
  22. package/assets/skills/meko-mcp-tools/references/tools-overview.md +32 -22
  23. package/assets/skills/meko-mcp-tools/references/tools-rag-workflow.md +14 -8
  24. package/assets/skills/meko-mcp-tools/references/tools-troubleshooting.md +45 -1
  25. package/assets/skills/meko-mcp-tools/references/tools-user-id-conventions.md +6 -39
  26. package/assets/skills/meko-mcp-tools-desktop/SKILL.md +54 -18
  27. package/assets/skills/meko-mcp-tools-desktop/desktop/README.md +1 -1
  28. package/assets/skills/meko-mcp-tools-desktop/references/_sections.md +1 -1
  29. package/assets/skills/meko-mcp-tools-desktop/references/tools-agent-id-conventions.md +8 -6
  30. package/assets/skills/meko-mcp-tools-desktop/references/tools-cookbook.md +95 -33
  31. package/assets/skills/meko-mcp-tools-desktop/references/tools-known-limitations.md +22 -5
  32. package/assets/skills/meko-mcp-tools-desktop/references/tools-memory-vs-conversation.md +14 -10
  33. package/assets/skills/meko-mcp-tools-desktop/references/tools-overview.md +35 -25
  34. package/assets/skills/meko-mcp-tools-desktop/references/tools-rag-workflow.md +14 -8
  35. package/assets/skills/meko-mcp-tools-desktop/references/tools-troubleshooting.md +67 -1
  36. package/assets/skills/meko-select-datapack-desktop/SKILL.md +4 -4
  37. package/assets/skills/meko-select-datapack-desktop/references/cookbook.md +5 -5
  38. package/assets/skills/meko-select-datapack-desktop/references/role-display-future.md +7 -5
  39. package/assets/skills/meko-select-datapack-desktop/references/troubleshooting.md +4 -4
  40. package/bin/create-meko-setup.mjs +70 -7
  41. package/lib/capture-cleanup.mjs +63 -0
  42. package/lib/clients/claude-code.mjs +1 -0
  43. package/lib/clients/codex.mjs +80 -35
  44. package/lib/clients/common.mjs +7 -0
  45. package/lib/clients/index.mjs +2 -0
  46. package/lib/clients/kiro.mjs +5 -5
  47. package/lib/clients/opencode.mjs +532 -0
  48. package/lib/config.mjs +68 -1
  49. package/lib/installer.mjs +18 -2
  50. package/lib/migrate/adapters/claude-code.mjs +11 -2
  51. package/lib/migrate/adapters/codex.mjs +9 -2
  52. package/lib/migrate/adapters/memory-md.mjs +27 -8
  53. package/lib/migrate/adapters/opencode.mjs +148 -0
  54. package/lib/migrate/claude-parser.mjs +153 -9
  55. package/lib/migrate/id.mjs +195 -13
  56. package/lib/migrate/mcp-client.mjs +25 -1
  57. package/lib/migrate/opencode-normalizer.mjs +132 -0
  58. package/lib/migrate/orchestrator.mjs +293 -77
  59. package/lib/migrate/progress.mjs +239 -5
  60. package/lib/migrate/registry.mjs +72 -0
  61. package/lib/migrate.mjs +96 -8
  62. package/package.json +1 -1
  63. package/scripts/bundle-assets.mjs +4 -0
@@ -4,15 +4,15 @@ description: Behavioral guide for AI agents using Meko MCP tools. Triggers when
4
4
  license: MIT
5
5
  metadata:
6
6
  author: Meko
7
- version: "3.1.0"
7
+ version: "3.2.0"
8
8
  tags: mcp, tools, datapack, memory, conversation, rag, meko
9
9
  ---
10
10
 
11
11
  # Meko MCP Tools — Agent Behavioral Guide
12
12
 
13
- Meko is agent-native data infrastructure that enables continuous learning from context windows through collective memory and shared knowledge. This skill teaches you how to use Meko's 23 MCP tools available in production.
13
+ Meko is agent-native data infrastructure that enables continuous learning from context windows through collective memory and shared knowledge. This skill teaches you how to use Meko's 25 MCP tools available in production.
14
14
 
15
- **Read this first.** On Claude Code, conversation capture is automatic (SessionStart / PreCompact / SessionEnd hooks) and the Meko server extracts durable memories from the captured turns on its own. Facts the user states in conversation are saved for you — you do **not** proactively call `memory_add` for them. Your active jobs are: **recall** what's already known (`memory_search`, `knowledgebase_search`), and the **few** save cases automatic extraction cannot reach. Details below.
15
+ **Read this first.** On Claude Code, conversation capture is automatic (SessionStart / PreCompact / SessionEnd hooks) and the Meko server extracts durable memories from the captured turns on its own. Facts the user states in conversation are saved for you — you do **not** proactively call `memory_add` for them. Your active jobs are: **recall** what's already known (`context_search` first, then `memory_search` or `knowledgebase_search` for a single source), and the **few** save cases automatic extraction cannot reach. Details below.
16
16
 
17
17
  ## Non-negotiable operating contracts
18
18
 
@@ -22,8 +22,8 @@ Apply these rules before the longer guidance below. They are service-contract sa
22
22
 
23
23
  Inspect the response envelope before its contents:
24
24
 
25
- 1. If `error` or an error-shaped `detail` is present, the search **failed** and its findings are **unknown**. Say exactly that. Never say "nothing was found," "no results," or "the store is empty."
26
- 2. Do not retry quota (`free_tier_limit_reached`) or permission errors. Report the error and stop. Retry only documented transient failures, with a bounded backoff.
25
+ 1. If `error` or an error-shaped `detail` is present, or the whole response is an error string (for example `Error searching memories: ...` or `[Errno 111] Connection refused`), the search **failed** and its findings are **unknown**. Say exactly that. Never say "nothing was found," "no results," or "the store is empty."
26
+ 2. Do not retry quota (`free_tier_limit_reached`), permission (403), or validation errors. Report the error and stop. The one exception is `datapack_access_denied`: retry it once, because the server's access check also fails closed on a transient database error. Retry only documented transient failures (see `tools-troubleshooting.md`), with a bounded backoff. For `PAT_RATE_LIMITED`, wait out the retry-after (about 60s) before retrying.
27
27
  3. Only a successful response with an explicit empty `results` array proves a legitimate empty search.
28
28
 
29
29
  ### 2. Treat `memory_get_all` as a recent window, never an export
@@ -39,6 +39,7 @@ If no candidate supports an answer, abstain: say the retrieved evidence does not
39
39
  ### 4. Verify writes and enforce real isolation
40
40
 
41
41
  - A success-shaped write response is not proof. Read back memories and conversations. For artifacts, compute SHA-256 locally, require the matching `content_hash`, then read back important bytes. A missing hash means the upload is unconfirmed.
42
+ - A read-back must use the same `datapack_id` as the write. Checking the default datapack after writing to a pinned one proves nothing.
42
43
  - `agent_id` attributes writes; it is not an access boundary. Put projects, tenants, or security domains that must not co-discover content in separate datapacks.
43
44
 
44
45
  ## `agent_id` — multi-agent identity
@@ -47,9 +48,11 @@ Use the SessionStart-injected `agent_id` verbatim. It normally has shape `<clien
47
48
 
48
49
  **Read scoping varies by tool:**
49
50
  - `memory_search` / `memory_get_all` — scoped to `(datapack_id, user_id)`; `agent_id` does not filter results. Do not fan out reads by agent.
50
- - `conversation_get` — agent-owned: pass the exact `agent_id` that created the conversation; any other value returns `agent_id_mismatch`.
51
+ - `conversation_get`, `conversation_add_message`, `conversation_update`, `conversation_delete`: agent-owned. Pass the exact `agent_id` that created the conversation; any other value returns `agent_id_mismatch`.
52
+ - `memory_delete_all`: deletes only the passed `agent_id`'s bucket, even though memory reads span every agent. A `memory_search` preview can show rows this call won't delete.
51
53
  - `conversation_list` — user/datapack scoped; `agent_id` is trace attribution only.
52
54
  - `knowledgebase_search` — datapack scoped; `agent_id` is ignored.
55
+ - `context_search`: the memory and KB buckets follow the rules above. The conversation bucket is broader than both: it spans every user and agent on the datapack, and `agent_id` doesn't filter it.
53
56
 
54
57
  See `tools-agent-id-conventions.md` for the full model, including how promotion works and how to phrase broad-query responses to the user. Legacy IDs remain readable through the same personal-memory read.
55
58
 
@@ -77,6 +80,8 @@ Meko context (inherited from parent session):
77
80
 
78
81
  Reuse the inherited conversation unless the parent or user explicitly requests a fresh scope. Always reuse the inherited agent ID.
79
82
 
83
+ Parallel subagents writing to one conversation have hit intermittent `not_found` or `agent_id_mismatch` ("conversation belongs to agent 'None'") on `conversation_add_message` right after `conversation_create`, while other subagents succeeded with identical arguments. Retry that call once with the same `seed` after a few seconds. If it still fails, don't create a replacement conversation: save the durable findings with `memory_add` and tell the parent the transcript for that subagent is incomplete.
84
+
80
85
  **You may be the subagent.** If no SessionStart context named a `conversation_id`, assume you are one and look for the block above in your prompt. If it is absent, do not guess, invent IDs, use the nil UUID, or write — ask the parent for both values.
81
86
 
82
87
  ## Core principle: capture is automatic — recall, don't re-store
@@ -93,7 +98,7 @@ Recall first; save only what capture cannot reach; never re-store a just-stated
93
98
  | User corrects a prior fact | Capture adds the correction but may retain the old fact; find and update/delete the stale memory when it must not survive. |
94
99
  | User explicitly says "remember this" / "save this to memory" | `memory_add` (verbatim). This is the clearest explicit-save case. |
95
100
  | A durable fact appears only in assistant output or a tool result | `memory_add`; automatic extraction reads the user turn. |
96
- | User asks "what do you know about X?" | Search both production retrieval surfaces: `memory_search` for personal context, then `knowledgebase_search` for shared datapack knowledge when relevant. |
101
+ | User asks "what do you know about X?" | `context_search`. One call returns separate memory, knowledge-base, and past-conversation buckets; report each. Confirm an empty memory or KB bucket with `memory_search` or `knowledgebase_search` before saying nothing is stored. |
97
102
  | User asks "what do we (as a team) know about X?" or about uploaded documents | `knowledgebase_search` (returns uploaded docs + promoted memories). |
98
103
  | User asks to share private memories | Follow the exact-ID `memory_promote` confirmation workflow below. |
99
104
  | User provides structured/tabular data (CSV, data dictionary) | Not natively supported via MCP. Point the user at the UI's Add Knowledge upload; do not `memory_add` row-by-row. |
@@ -122,6 +127,8 @@ memory_search(query="destructive <action type> preferences feedback",
122
127
 
123
128
  A single search covers all of this user's agents. Memory is supplemental evidence, not authorization: a relevant preference can require more caution, but an empty search never authorizes destruction. Follow host approval rules and prefer previews.
124
129
 
130
+ If your host's policy doesn't let you run a Meko delete tool even when the user asks, say so plainly and hand the user what they need to do it themselves: the exact memory or conversation IDs, a one-line summary of each, and the tool call to run from a client that allows deletes. Don't report the data as deleted.
131
+
125
132
  ### Capture rules
126
133
 
127
134
  - **Verbatim content only** — never summarize, rephrase, or condense. See `tools-memory-vs-conversation.md`.
@@ -129,6 +136,21 @@ A single search covers all of this user's agents. Memory is supplemental evidenc
129
136
  - **Always use a seed** — enables dedup across the three capture mechanisms.
130
137
  - **Graceful failure** — if `conversation_add_message` fails, log the error and continue. Do not retry more than once.
131
138
 
139
+ ### Long-running conversations
140
+
141
+ Meko stores a conversation as one Langfuse trace, and Langfuse refuses to load a trace larger than its size limit. After a long session crosses that limit, reads of the session's own conversation fail even though the conversation exists:
142
+
143
+ - `conversation_get` and `conversation_update` return `{"error": "not_found", "detail": "Conversation <id> not found"}`, or the call times out.
144
+ - On servers without the MEKO-714 fix, `conversation_add_message` returns the same `not_found`.
145
+
146
+ When this happens on the conversation you've been using all session, accept the error and keep working:
147
+
148
+ - Don't retry the call, create a replacement conversation, or replay earlier messages. Each replay makes the trace larger, and recreating the conversation has caused capture loops.
149
+ - Skip the read-back for that conversation. Tell the user once that Meko can't load this conversation because it's too large, and don't report it as data loss.
150
+ - Keep using `context_search`, the `memory_*` tools, and `knowledgebase_search`. They don't load the conversation trace.
151
+
152
+ A `not_found` for a conversation you just created, or one this session never wrote to, has other causes; see `tools-troubleshooting.md`.
153
+
132
154
  ## Calling tools correctly on the first attempt
133
155
 
134
156
  **Use only the required parameters. Do not guess optional parameters.**
@@ -150,6 +172,27 @@ Required parameters: `text`, `conversation_id`. On **writes**, `conversation_id`
150
172
 
151
173
  **Write one coherent fact per memory**, with the identifiers a later search will use — never a transcript or multi-topic dump; focused memories retrieve better and read far faster.
152
174
 
175
+ ### context_search: default first call for recall
176
+
177
+ ```
178
+ context_search(
179
+ query="auth migration decisions",
180
+ agent_id="<your-agent-id>",
181
+ conversation_id="<session_conversation_id>",
182
+ datapack_id="<pinned datapack UUID, if any>")
183
+ ```
184
+
185
+ Required parameters: `query`, `conversation_id`. It queries memory, the knowledge base, and the conversation-history cache in parallel and returns `{"results": {"memory": [...], "knowledge_base": [...], "conversation": {"hits": [...], "thread": [...]}}, "token_savings": {...}}`.
186
+
187
+ - Read every bucket. A KB document can supersede a memory or a past conversation; nothing is hidden by another source's hit.
188
+ - An empty bucket is ambiguous: either that source found nothing relevant, or it failed. `context_search` turns a failed source into an empty list and records the error only in the trace. Before you tell the user nothing is stored about X, confirm with `memory_search` or `knowledgebase_search`, which return errors.
189
+ - A bucket is `null` only when that source wasn't queried: `force_source` excluded it, or the server couldn't build a query vector for it.
190
+ - The conversation bucket is datapack-wide. It returns embedded turns from every user and agent on the datapack, and each hit carries its author's `user_id`. Don't present a hit as this user's own history.
191
+ - `limit` bounds the memory and KB buckets only; the conversation bucket returns up to 10 hits plus a thread of whole turns.
192
+ - The memory bucket has no similarity floor on the default path, so it can contain weak rows. Discount them against the other buckets instead of treating them as answers.
193
+ - Set `force_source` to `"memory"`, `"knowledge_base"`, or `"conversation"` only when you already know the one source you need.
194
+ - Use `memory_search` or `knowledgebase_search` directly when you need `run_id` filtering, the memory similarity floor, or exact document IDs for `knowledgebase_delete_document`.
195
+
153
196
  ### memory_search — correct call pattern
154
197
 
155
198
  ```
@@ -159,9 +202,9 @@ memory_search(
159
202
  conversation_id="<session_conversation_id>")
160
203
  ```
161
204
 
162
- Required parameters: `query`, `agent_id`, `conversation_id`. On **`memory_search`** specifically, `conversation_id` is used only for Langfuse trace nesting — it does NOT filter results. Pass the session's UUID so the search span appears under the active conversation in Observe; passing `""` is accepted and means "don't nest under any trace."
205
+ Required parameters: `query`, `conversation_id`. On **`memory_search`** specifically, `conversation_id` is used only for Langfuse trace nesting — it does NOT filter results. Pass the session's UUID so the search span appears under the active conversation in Observe. Never pass `""`: production `memory_search` currently fails on an empty value (MEKO-707). If you have no conversation yet, pass a freshly generated 32-character lowercase hex id (a UUID with the hyphens removed); on a read it only nests the trace.
163
206
 
164
- `agent_id` does not filter what `memory_search` returns — one call covers every agent's rows for this user, including the `meko_agent` bucket (see Read scoping above).
207
+ `agent_id` does not filter what `memory_search` returns — one call covers every agent's rows for this user, including the `meko_agent` bucket (see Read scoping above). Results below a server-configured similarity floor (default 0.2) are dropped, so an empty `results` list can mean "only weak matches", not "nothing stored".
165
208
 
166
209
  Evidence going into reasoning follows operating contract 3 (retrieve ≤ ~25, pass ≤ ~10).
167
210
 
@@ -180,7 +223,7 @@ knowledgebase_search(
180
223
  limit=10)
181
224
  ```
182
225
 
183
- Required parameters: `query`, `agent_id`, `conversation_id`, `datapack_id`. `datapack_id` has no default here. `agent_id` is ignored for filtering — results are the team's shared knowledge on the datapack regardless of what you pass.
226
+ Required parameters: `query`, `conversation_id`, `datapack_id`. `datapack_id` has no default here. `agent_id` is ignored for filtering — results are the team's shared knowledge on the datapack regardless of what you pass.
184
227
 
185
228
  For recalling working memories — especially recently-changed facts — prefer `memory_search`; the knowledge base is the team's publish/archive surface.
186
229
 
@@ -201,7 +244,7 @@ The Cloud UI's Learnings tab remains an alternative user-driven path.
201
244
  ### Critical parameter rules
202
245
 
203
246
  - **agent_id**: Per-session value, injected via `additionalContext` by the SessionStart hook. Shape: `<client>:<repo-basename>`. Pass verbatim on project-scoped writes and reads. Pass `"meko_agent"` for the cross-project common bucket (or empty/omit — server rewrites empty to `meko_agent`). Ignored on `knowledgebase_search`. See `tools-agent-id-conventions.md`.
204
- - **conversation_id**: the conversation's ID *is* its trace ID, so every call carrying it becomes a span under that conversation in the Observe hub. On write tools (`memory_add`, `conversation_add_message`) pass a real UUID from `conversation_create` or the SessionStart hook — a nil/empty value orphans the trace. On `memory_search` it only nests the trace (it does not filter), and empty-string is accepted; on `memory_get_all` and most read tools, still pass the session UUID when you have one. Never pass `"current"` or other non-UUID junk.
247
+ - **conversation_id**: the conversation's ID *is* its trace ID, so every call carrying it becomes a span under that conversation in the Observe hub. On write tools (`memory_add`, `conversation_add_message`) pass a real UUID from `conversation_create` or the SessionStart hook — a nil/empty value orphans the trace. On read tools it only nests the trace (it does not filter), but it must still be a 32-hex id: `memory_search` fails on `""`, and most other tools reject it with `conversation_id_required`. Never pass `"current"` or other non-UUID junk.
205
248
  - **When in doubt about optional parameters, omit them.** The server has sensible defaults.
206
249
 
207
250
  ### Verify after writing
@@ -209,7 +252,7 @@ The Cloud UI's Learnings tab remains an alternative user-driven path.
209
252
  Never confirm a successful save to the user without first validating via a read-back. `{"status": "accepted"}` or HTTP 200 from a write tool is not proof of persistence — indexing lag, silent server errors, and wrong-datapack routing all surface as "the write looked fine but nothing is there." Always read back before reporting success.
210
253
 
211
254
  - **After `memory_add`**: call `memory_search` with a distinctive token from the stored text (a name, UUID, rare phrase — not a common word). Assert the new memory appears in the results. Only then tell the user it was saved.
212
- - **After `conversation_add_message`**: call `conversation_get(include_messages=true)` with the returned `conversation_id`. Assert `message_count` > 0 and that the new message is in the returned list.
255
+ - **After `conversation_add_message`**: call `conversation_get(include_messages=true)` with the returned `conversation_id`. Assert `message_count` > 0 and that the new message is in the returned list. On a long conversation whose trace is too large for Langfuse, `conversation_get` returns `not_found` even though the write landed. Follow "Long-running conversations" above instead of re-posting or recreating the conversation.
213
256
  - **After `artifact_put`**: operating contract 4 — the locally-computed SHA-256 must match the returned `content_hash` (a rate-limited or errored put carries **none**); read back important artifacts via `artifact_get` and compare bytes.
214
257
  - **On verification failure**: tell the user the save did not succeed — do **not** claim it did. Include the verification-failure detail (empty search, missing message, HTTP error) so they can act — wrong datapack, scope mismatch, expired API key are the common causes.
215
258
 
@@ -234,13 +277,13 @@ On the first Meko tool call in a fresh session (no prior Meko tool call since pr
234
277
 
235
278
  ## Budgeting calls
236
279
 
237
- `memory_add` takes ~10s for a one-line fact and ~20-30s for document-sized text; `memory_search` ~2-6s. Sustained bulk ingest throttles to roughly per-call latency — run large ingests as background jobs. `memory_search`, `knowledgebase_search`, and `memory_add` also draw from **lifetime per-user quotas** on Free/Standard tiers, so budget latency *and* call count. `datapack_id` is optional on most tools (default datapack) but **required** on `knowledgebase_search`. See `tools-known-limitations.md`.
280
+ `memory_add` takes ~10s for a one-line fact and ~20-30s for document-sized text; `memory_search` ~2-6s. Sustained bulk ingest throttles to roughly per-call latency — run large ingests as background jobs. `memory_search`, `knowledgebase_search`, and `memory_add` also draw from **lifetime per-user quotas** on Free/Standard tiers, and `context_search` and `conversation_add_message` on the Free tier, so budget latency *and* call count. `datapack_id` is optional on most tools (default datapack) but **required** on `knowledgebase_search`. See `tools-known-limitations.md`.
238
281
 
239
282
  ## Reference sections
240
283
 
241
284
  | File | What it covers |
242
285
  |------|---------------|
243
- | `tools-overview.md` | Complete catalog of all 23 tools available in production, with decision tree |
286
+ | `tools-overview.md` | Complete catalog of all 25 tools available in production, with decision tree |
244
287
  | `tools-cookbook.md` | Per-tool examples with correct parameters, responses, and error cases |
245
288
  | `tools-memory-vs-conversation.md` | When to use memory tools vs conversation tools |
246
289
  | `tools-datapack-workflow.md` | Datapack lifecycle and datapack_id routing |
@@ -6,7 +6,7 @@ description: Maps reference files to their topics for the meko-mcp-tools skill
6
6
  # Reference Sections
7
7
 
8
8
  ## Tool Selection & Catalog
9
- - [tools-overview.md](tools-overview.md) — Complete catalog of all 23 tools available in production, with a decision tree
9
+ - [tools-overview.md](tools-overview.md) — Complete catalog of all 25 tools available in production, with a decision tree
10
10
 
11
11
  ## Tool-Specific Guidance
12
12
  - [tools-memory-vs-conversation.md](tools-memory-vs-conversation.md) — Decision framework: memory_add vs conversation_create/conversation_add_message
@@ -18,7 +18,7 @@ description: Maps reference files to their topics for the meko-mcp-tools skill
18
18
 
19
19
  ## Conventions & Deduplication
20
20
  - [tools-agent-id-conventions.md](tools-agent-id-conventions.md) — agent_id naming rules, hyphen prohibition, and namespace isolation
21
- - [tools-user-id-conventions.md](tools-user-id-conventions.md) — user_id vs agent_id: when to pass each, and how they scope memory
21
+ - [tools-user-id-conventions.md](tools-user-id-conventions.md) — how the server resolves user_id from your credentials, and how it and agent_id scope memory
22
22
  - [tools-conversation-dedup.md](tools-conversation-dedup.md) — Seed-based deterministic trace IDs for Langfuse deduplication
23
23
 
24
24
  ## Practical Usage
@@ -14,7 +14,16 @@ Each memory is written under an `agent_id` (stored on the row, shown as the UI b
14
14
  | Loose client name | Non-coding agents (Claude Desktop, generic MCP clients) where there's no project concept. | `claude_desktop` |
15
15
  | `meko_agent` | Cross-project common bucket — facts any agent should see regardless of project (user identity, global preferences). The server stores empty/missing `agent_id` here automatically. | `meko_agent` |
16
16
 
17
- **Discover the value at session start.** The SessionStart hook injects the chosen `agent_id` into the first-turn `additionalContext` based on the cwd's repo basename. Use that value verbatim — do not re-derive it. If the block is absent, fall back to `<client>:<basename(cwd)>` or ask the user.
17
+ **Discover the value at session start.** The SessionStart hook injects the chosen `agent_id` into the first-turn `additionalContext`. Project-scoped ids are derived by walking parents of the session cwd for `.git` and taking the repo-root basename; the walk stops at `$HOME`, so a git-tracked home directory does not claim every directory beneath it. Sessions outside any repo get the bare client name (`claude_code`), not a leaf basename.
18
+
19
+ Use the injected value verbatim — do not re-derive it. A resumed session, or one that re-fires SessionStart (`/clear`, `/compact`), keeps the bucket its conversation already belongs to, and `MEKO_AGENT_ID` overrides either, so the injected value is not always what a fresh derivation would produce. If the block is absent, ask the user rather than guessing from the raw cwd basename (sibling directories like `docs/` or `webapp/` in unrelated repos would collide).
20
+
21
+ MEKO-590 changed new coding-session ids from the cwd leaf to the repository
22
+ root. Existing ownership does not change in place: migration checkpoints and
23
+ Kiro session intents keep their persisted pre-MEKO-590 id, because the server
24
+ does not allow an existing conversation's owner to change. Datapack pins also
25
+ fall back to the old cwd-leaf filename until the user pins or clears again.
26
+ New sessions without persisted state use the repository-root id.
18
27
 
19
28
  For genuinely cross-project facts ("the user's name is Alice", "the user prefers dark mode") write with `agent_id="meko_agent"` so their attribution clearly identifies the common cross-project bucket.
20
29
 
@@ -42,7 +51,7 @@ Filter tuple: `(datapack_id, user_id)`. `agent_id` is **not** applied on memory
42
51
 
43
52
  ### Personal conversation reads — `conversation_get`, `conversation_list`
44
53
 
45
- - `conversation_get` — agent-owned. Filter tuple `(datapack_id, user_id, agent_id)`: pass the exact `agent_id` that created the conversation; a wrong value returns `agent_id_mismatch`.
54
+ - `conversation_get`, `conversation_add_message`, `conversation_update`, `conversation_delete` — agent-owned. Filter tuple `(datapack_id, user_id, agent_id)`: pass the exact `agent_id` that created the conversation; a wrong value returns `agent_id_mismatch`.
46
55
  - `conversation_list` — **not** agent-filtered. It lists by `(datapack_id, user_id)` only; `agent_id` on the call is trace-attribution only (like memory reads), so one call returns the datapack's conversations for your user regardless of which agent created them.
47
56
 
48
57
  ### Team-shared reads — `knowledgebase_search`
@@ -81,13 +90,12 @@ knowledgebase_search(agent_id=anything, query=...)
81
90
 
82
91
  ## When to use what — broad-query guidance
83
92
 
84
- If the user asks "what do you know about X?": one `memory_search` covers the whole personal surface (every `agent_id`, nothing to fan out), then `knowledgebase_search` for team-shared knowledge. Tell the user which surface each finding came from.
93
+ If the user asks "what do you know about X?": one `context_search` returns the whole personal memory surface (every `agent_id`, nothing to fan out), team-shared knowledge, and matching past-conversation turns in separate buckets. Tell the user which surface each finding came from. Conversation hits can come from other users on the datapack.
85
94
 
86
95
  ## Optional sub-scoping
87
96
 
88
97
  Optional parameters can narrow a call further:
89
- - `user_id` — explicitly scope writes/reads to a specific end-user if your agent serves multiple (rare in Claude Code; more common in API products)
90
- - `run_id` — on `memory_search` and the delete tools it is a **read/delete
98
+ - `run_id` — on `memory_search` and `memory_delete_all` it is a **read/delete
91
99
  filter** on the row's `meko_conversation_id`, so pass a *conversation id* to
92
100
  scope the call to that conversation (consistent scoping landed in
93
101
  MEKO-473/MEKO-474, #271). On `memory_add` it is Langfuse trace metadata only
@@ -95,10 +103,10 @@ Optional parameters can narrow a call further:
95
103
  `conversation_id` — a row written with `memory_add(run_id=X)` is not findable
96
104
  via `memory_search(run_id=X)`.
97
105
 
98
- Available on `memory_add`, `memory_search`, `memory_get_all`, `memory_delete_all`, `conversation_create`, `conversation_list`.
106
+ Accepted by `memory_add`, `memory_search`, `memory_get_all`, `memory_delete_all`, and `conversation_create`. `memory_get_all` ignores it. No tool takes a `user_id` argument; the server resolves it from your credentials (see `tools-user-id-conventions.md`).
99
107
 
100
108
  ## Things I checked and found in-data on real Cloud datapacks
101
109
 
102
110
  - `agent_id="agent"` appears on many legacy rows — it was the previous canonical constant. New writes should use the schema in the table above; memory reads still return the legacy rows.
103
- - Memory Summary UI (`/datapacks/<name>/memory-summary`) is agent-id-agnostic — shows every row in the datapack, renders the stored `agent_id` as a badge. `memory_search` and `conversation_list` are likewise agent-agnostic (they return all your agents' rows for the user); only `conversation_get` enforces `agent_id` (agent ownership).
111
+ - Memory Summary UI (`/datapacks/<name>/memory-summary`) is agent-id-agnostic — shows every row in the datapack, renders the stored `agent_id` as a badge. `memory_search` and `conversation_list` are likewise agent-agnostic (they return all your agents' rows for the user); the conversation calls (`conversation_get`, `conversation_add_message`, `conversation_update`, `conversation_delete`) enforce `agent_id` (agent ownership), and `memory_delete_all` deletes only the passed `agent_id`'s bucket.
104
112
  - Subagents spawned via the `Agent` tool in Claude Code do not automatically inherit the parent's `agent_id`. The parent must inject it into the spawn prompt. See the SKILL.md "When spawning subagents" section.
@@ -6,6 +6,47 @@ Every tool example below shows the correct parameters, expected response, and co
6
6
 
7
7
  ---
8
8
 
9
+ ## Retrieval
10
+
11
+ ### context_search
12
+
13
+ Default first call for open-ended recall ("what do you know about X?"). One call queries memory, the knowledge base, and the conversation-history cache in parallel.
14
+
15
+ ```
16
+ context_search(
17
+ query="auth migration decisions",
18
+ agent_id="<your agent_id>",
19
+ conversation_id="<session conversation id>",
20
+ datapack_id="<datapack UUID>")
21
+ ```
22
+
23
+ Required: `query`, `conversation_id`. `datapack_id` is optional (default datapack if omitted); pass the pinned id when you have one.
24
+
25
+ Response:
26
+
27
+ ```
28
+ {
29
+ "results": {
30
+ "memory": [{"id": "...", "memory": "...", "score": 0.51, ...}],
31
+ "knowledge_base": [{"id": "...", "chunk_text": "...", "document_id": "...", "distance": 0.31, "match_type": "hybrid", ...}],
32
+ "conversation": {"hits": [...], "thread": [...]}
33
+ },
34
+ "token_savings": {"total_tokens": 49000, "memory": {"tokens_sent": 600, "tokens_saved": 48400}, "tokens_saved": 48400}
35
+ }
36
+ ```
37
+
38
+ - A bucket is `null` only when that source wasn't queried: `force_source` excluded it, or the server couldn't build a query vector for it.
39
+ - An empty bucket is ambiguous: either that source found nothing relevant, or it failed. `context_search` turns a failed source into an empty list and records the error only in the trace. Before you tell the user nothing is stored about X, confirm with `memory_search` or `knowledgebase_search`, which return errors.
40
+ - The conversation bucket is datapack-wide. It returns embedded turns from every user and agent on the datapack, and each hit carries its author's `user_id`. Don't present a hit as this user's own history.
41
+ - `limit` bounds the memory and KB buckets only; the conversation bucket returns up to 10 hits plus a thread of whole turns.
42
+ - The memory bucket has no similarity floor on the default path. The KB bucket drops chunks above an absolute distance cutoff, so it can be empty even when `knowledgebase_search` would return a weak best match.
43
+ - `force_source="memory" | "knowledge_base" | "conversation"` queries only that source. `force_source="memory"` reapplies the `memory_search` similarity floor.
44
+ - `token_savings` is an estimate for reporting. Don't base decisions on it.
45
+
46
+ **Errors:** `conversation_id_required`, `invalid_force_source`, `datapack_access_denied`, and `free_tier_limit_reached` (Free tier: 1,000 lifetime calls). Treat any error as a failed search (SKILL.md operating contract 1).
47
+
48
+ ---
49
+
9
50
  ## Memory Tools
10
51
 
11
52
  **Critical:** Pass your session's `agent_id` on every memory *write* (from the SessionStart `additionalContext`) — it is stored on the row as attribution. It does **not** filter reads: one `memory_search` / `memory_get_all` returns all of your memories across every `agent_id`. For cross-project facts, write with `agent_id="meko_agent"`.
@@ -46,13 +87,15 @@ memory_search(query="What programming language does the team use?", agent_id="ag
46
87
 
47
88
  **Cross-conversation discovery.** `memory_search` returns hits across every stored conversation for the `(datapack_id, user_id)` pair, across all agents (`agent_id` scopes the call's trace, not the results). When a hit references an interesting conversation, follow up with `conversation_list` to browse the associated threads and `conversation_get` to read a specific one — the memory hit's `meko_conversation_id` field is the id to fetch. For a deliberately cross-conversation search leave `run_id` off; to scope a search to a single conversation instead, pass `run_id=<conversation_id>` (it filters on `meko_conversation_id` — see `tools-known-limitations.md`).
48
89
 
49
- **Relevance floor.** Vector-matched `results` below `MEMORY_SEARCH_MIN_SCORE` (mem0's cosine-similarity score, default `0.5`) are dropped as weak matches rather than returned. A query can come back with fewer results than `limit`, or an empty list, when nothing clears the bar; that means no sufficiently relevant memory, not a broken call.
90
+ **Relevance floor.** `memory_search` drops results whose raw cosine similarity is below the server's `memory_search_min_score` setting (default `0.2`, tunable at runtime). A query can return fewer results than `limit`, or an empty list, when nothing clears the bar. That means no sufficiently relevant memory, not a broken call.
50
91
 
51
92
  **Response:**
52
93
  ```json
53
- {"results": [{"id": "mem-uuid-123", "memory": "Team uses Python for backend", "score": 0.89}]}
94
+ {"results": [{"id": "mem-uuid-123", "memory": "Team uses Python for backend", "score": 0.89, "raw_similarity_score": 0.72}]}
54
95
  ```
55
96
 
97
+ `score` is the fused hybrid rank (semantic + keyword + entity boost) used to order results; `raw_similarity_score` is the unfused cosine value. A similarity threshold like `MEMORY_SEARCH_MIN_SCORE` gates on `raw_similarity_score` when it is not null, and falls back to `score` when the raw field is absent or null.
98
+
56
99
  **With limit:**
57
100
  ```
58
101
  memory_search(query="user preferences", agent_id="agent", conversation_id="<uuid>", limit=5)
@@ -64,7 +107,7 @@ memory_search(query="user preferences", agent_id="agent", conversation_id="<uuid
64
107
 
65
108
  ### memory_get_all
66
109
 
67
- **When to use:** List all of your memories for this user — across every `agent_id` (`agent_id` does not filter the result). Useful at session start to load context.
110
+ **When to use:** See the most recent memories (about 20 rows) across every `agent_id`, plus the true `total`. It is not a complete listing and takes no paging arguments (SKILL.md operating contract 2). Use `memory_search` or `memory_get_by_id` for anything older or specific.
68
111
 
69
112
  ```
70
113
  memory_get_all(agent_id="agent", conversation_id="<uuid>")
@@ -96,11 +139,13 @@ memory_update(memory_id="mem-uuid-123", text="Updated: Team uses Go for all new
96
139
  memory_delete_by_id(memory_id="mem-uuid-123", agent_id="agent", conversation_id="<uuid>")
97
140
  ```
98
141
 
142
+ `memory_update` and `memory_delete_by_id` return `memory_is_promoted` for a promoted memory, and `not_found` for an id that is missing or belongs to another account.
143
+
99
144
  ---
100
145
 
101
146
  ### memory_delete_all
102
147
 
103
- **Destructive.** Deletes all memories for the agent. For removing a single memory, prefer `memory_delete_by_id` — `memory_delete_all` wipes the entire agent scope in the datapack.
148
+ **Destructive.** Deletes all memories in the passed `agent_id`'s bucket in the datapack. It does not touch other agents' rows, even though `memory_search` shows them; omitting `agent_id` deletes only the `meko_agent` bucket. Pass `run_id=<conversation_id>` to limit it to one conversation. For removing a single memory, prefer `memory_delete_by_id`.
104
149
 
105
150
  ```
106
151
  memory_delete_all(agent_id="agent", conversation_id="<uuid>")
@@ -134,9 +179,12 @@ Get exact UUIDs from the `id` field of `memory_search` / `memory_get_all` result
134
179
 
135
180
  ```
136
181
  conversation_create(agent_id="agent",
137
- title="Debugging the auth middleware")
182
+ title="Debugging the auth middleware",
183
+ datapack_id="<uuid from datapack_list>")
138
184
  ```
139
185
 
186
+ `datapack_id` is required whenever no server-side default resolves for the caller. Omitting it in that state returns `{"error": "datapack_id_required"}` and persists nothing; the same contract applies to `conversation_add_message`, `conversation_get`, `conversation_update`, and `conversation_delete`.
187
+
140
188
  **Response:**
141
189
  ```json
142
190
  {"id": "conv-uuid-123", "title": "Debugging the auth middleware"}
@@ -207,7 +255,7 @@ conversation_delete(conversation_id="conv-uuid-123", agent_id="agent")
207
255
 
208
256
  ## Knowledge Base Tools
209
257
 
210
- **KB ingestion is a UI-only activity.** Users upload files via the datapack's Actions → **Add Knowledge** dialog (PDF/TXT/MD/JSON/MP4, 5MB each, 10/batch). `knowledgebase_search` is the one KB tool exposed via MCP.
258
+ **KB ingestion is a UI-only activity.** Users upload files via the datapack's Actions → **Add Knowledge** dialog (PDF/TXT/MD/JSON/MP4, 5MB each, 10/batch). MCP exposes two KB tools: `knowledgebase_search`, and `knowledgebase_delete_document` for removing a single uploaded file.
211
259
 
212
260
  See `tools-rag-workflow.md` for the decision table.
213
261
 
@@ -235,6 +283,17 @@ Populated KBs return results with chunk content and similarity scores. An empty/
235
283
 
236
284
  ---
237
285
 
286
+ ### knowledgebase_delete_document
287
+
288
+ Permanently deletes ONE knowledge-base file — its chunks and metadata in one transaction, plus a best-effort delete of the stored file. Irreversible: confirm with the user before calling, and take `document_id` from `knowledgebase_search` hits — hits carry `document_id` but NOT a filename, so confirm by echoing the id and the matched chunk text (the documents list API / Meko UI is the authoritative name source). Never guess an id; non-UUID values are rejected.
289
+
290
+ ```
291
+ knowledgebase_delete_document(document_id="<uuid from a search hit>",
292
+ conversation_id="<session conversation id>")
293
+ ```
294
+
295
+ Returns `{"document_id", "chunks_deleted", "s3_deleted"}` — if `s3_deleted` is `false`, say so: the index entries are gone but the stored file may remain. Errors include a numeric `status`: `403` means the user is not the datapack owner, a maintainer, or the file's uploader — report it, don't retry; `409` (`DOCUMENT_PROCESSING`) means the file is still being indexed — wait for indexing to finish, then retry.
296
+
238
297
  ## Artifact Tools
239
298
 
240
299
  ### artifact_put
@@ -322,11 +381,24 @@ For large files use the `local_path` value to read the file with normal file too
322
381
  ### datapack_create / datapack_list / datapack_describe
323
382
 
324
383
  ```
325
- datapack_create(name="analytics_prod")
384
+ datapack_create(name="analytics_prod", conversation_id="<conversation id>")
326
385
  datapack_list(conversation_id="<session conversation id>") # returns datapack_id for each datapack
327
- datapack_describe(datapack_id="<uuid>", include_status=True)
386
+ datapack_describe(datapack_id="<uuid>", include_status=True, conversation_id="<conversation id>")
328
387
  ```
329
388
 
389
+ `datapack_describe` returns these counts:
390
+
391
+ | Field | Meaning |
392
+ |---|---|
393
+ | `memory_count` | All memories stored in the datapack |
394
+ | `collective_memory_count` | Memories promoted to shared knowledge |
395
+ | `learnings_count` | Memories awaiting a promotion decision |
396
+ | `knowledge_base_file_count` | Uploaded KB documents; `null` if the status endpoint is unreachable |
397
+ | `knowledge_chunk_count` | KB chunks across all documents (for debugging retrieval) |
398
+ | `shared_knowledge_count` | `collective_memory_count + knowledge_base_file_count`; `null` when the file count is `null` |
399
+
400
+ `knowledge_count` is a deprecated alias of `knowledge_chunk_count`. `datapack_list` doesn't compute counts; call `datapack_describe` for them.
401
+
330
402
  ### datapack_update / datapack_delete
331
403
 
332
404
  `datapack_update` renames a datapack, edits its description, and/or opts it in/out of conversation-search embedding. `name`, `description`, and `conversation_search_opt_out` are all optional; pass at least one. If none are provided the tool returns `nothing_to_update` without hitting the API.
@@ -334,11 +406,11 @@ datapack_describe(datapack_id="<uuid>", include_status=True)
334
406
  The server refuses to rename the caller's `meko_default_datapack` — a rename call against that datapack returns `"meko_default_datapack cannot be renamed"`. Description edits on the default datapack are still allowed. Passing `description=""` does NOT clear an existing description; clearing is not supported via MCP. Conversation-search embedding is on by default; `conversation_search_opt_out=True` stops future turns from being indexed (already-cached turns are unaffected) and is restricted to the datapack's owner or a maintainer. This is best-effort, not a hard guarantee — a transient database error on the live embed path's opt-out check fails open, so a turn can occasionally still get embedded for an opted-out datapack.
335
407
 
336
408
  ```
337
- datapack_update(datapack_id="<uuid>", name="renamed-datapack")
338
- datapack_update(datapack_id="<uuid>", description="new description")
339
- datapack_update(datapack_id="<uuid>", name="x", description="y")
340
- datapack_update(datapack_id="<uuid>", conversation_search_opt_out=True)
341
- datapack_delete(datapack_id="<uuid>") # Irreversible!
409
+ datapack_update(datapack_id="<uuid>", name="renamed-datapack", conversation_id="<conversation id>")
410
+ datapack_update(datapack_id="<uuid>", description="new description", conversation_id="<conversation id>")
411
+ datapack_update(datapack_id="<uuid>", name="x", description="y", conversation_id="<conversation id>")
412
+ datapack_update(datapack_id="<uuid>", conversation_search_opt_out=True, conversation_id="<conversation id>")
413
+ datapack_delete(datapack_id="<uuid>", conversation_id="<conversation id>") # Irreversible!
342
414
  ```
343
415
 
344
416
  ### Agent and knowledge-base management (NOT MCP — control-plane only)
@@ -348,4 +420,4 @@ Agent and KB lifecycle does not ship as MCP tools. If the user asks to create/li
348
420
  - REST: `POST/GET/DELETE /datapacks/:datapack_id/agents` (agents), `POST/GET/DELETE /datapacks/:datapack_id/knowledge-bases` (KB sources).
349
421
  - Or the Meko Cloud UI at `cloud.mekodata.ai` → Datapacks → agents / knowledge-bases.
350
422
 
351
- KB ingestion specifically lives in the UI today: Datapack → Actions → **Add Knowledge** (PDF/TXT/MD/JSON/MP4, 5 MB each, 10/batch). Agents querying a populated index use `knowledgebase_search` — see `tools-rag-workflow.md`.
423
+ KB ingestion specifically lives in the UI today: Datapack → Actions → **Add Knowledge** (PDF/TXT/MD/JSON/MP4, 5 MB each, 10/batch). Agents querying a populated index use `knowledgebase_search`, and can remove a single uploaded file with `knowledgebase_delete_document` — see `tools-rag-workflow.md`.
@@ -50,7 +50,7 @@ Delete child resources first (agents and KB sources via the control plane), then
50
50
  ```
51
51
  # Control-plane (REST or UI): DELETE /datapacks/:datapack_id/knowledge-bases
52
52
  # Control-plane (REST or UI): DELETE /datapacks/:datapack_id/agents/sales_agent
53
- datapack_delete(datapack_id="dp-uuid-123") # MCP-exposed, destructive, irreversible
53
+ datapack_delete(datapack_id="dp-uuid-123", conversation_id="<conversation id>") # MCP-exposed, destructive, irreversible
54
54
  ```
55
55
 
56
56
  ## Common mistake: forgetting datapack_id on memory tools
@@ -12,6 +12,10 @@ These are current limitations of the Meko MCP tools. Know them upfront to avoid
12
12
  | Standard | 5,000 | 5,000 | 30,000 |
13
13
  | Pro / Enterprise | uncapped | uncapped | uncapped |
14
14
 
15
+ The Free tier also caps `context_search` and `conversation_add_message` at 1,000 calls each. Embedding turns into the conversation-search cache has its own cap (2,000 turns on Free, 10,000 on Pro). When that cap is reached, `conversation_add_message` still stores the turn and reports `conversation_search_skipped: "quota_exceeded"`; the turn just won't appear in `context_search`'s conversation bucket.
16
+
17
+ A quota error can arrive with HTTP 403. It is not an authentication failure; don't reconfigure credentials because of it.
18
+
15
19
  When the cap is reached the tool returns an error object with code `free_tier_limit_reached` (on every tier; the `tier` field names the capped tier) and **no `results` key**.
16
20
 
17
21
  - **Do not retry** — the cap is lifetime.
@@ -24,9 +28,19 @@ One call returns roughly the **20 most recent rows**; the response's `total` rep
24
28
 
25
29
  ## run_id is a read/delete filter on the conversation id, not a write key
26
30
 
27
- `memory_search(run_id=<conversation_id>)` and the memory delete tools filter on the row's `meko_conversation_id`, so passing a conversation id there correctly scopes the call to that one conversation — a supported, reliable way to read a single conversation's memories (read/write/delete scoping was made consistent in MEKO-473/MEKO-474, #271). The one gotcha is on the write side: `memory_add`'s own `run_id` is Langfuse trace metadata only and is **not** persisted as the row's conversation id, so a row written with `memory_add(run_id=X)` is not findable via `memory_search(run_id=X)`. Scope writes with `conversation_id`, then filter the matching read by that same id.
31
+ `memory_search(run_id=<conversation_id>)` and `memory_delete_all(run_id=<conversation_id>)` filter on the row's `meko_conversation_id`, so passing a conversation id there correctly scopes the call to that one conversation — a supported, reliable way to read a single conversation's memories (read/write/delete scoping was made consistent in MEKO-473/MEKO-474, #271). The one gotcha is on the write side: `memory_add`'s own `run_id` is Langfuse trace metadata only and is **not** persisted as the row's conversation id, so a row written with `memory_add(run_id=X)` is not findable via `memory_search(run_id=X)`. Scope writes with `conversation_id`, then filter the matching read by that same id.
32
+
33
+ `memory_get_all` accepts `run_id` but ignores it, and `conversation_list` has no `run_id`.
34
+
35
+ ## memory_delete_all is agent-scoped; memory reads are not
36
+
37
+ `memory_search` and `memory_get_all` return every agent's rows for the user. `memory_delete_all` deletes only rows in the `agent_id` you pass, and an omitted `agent_id` means the `meko_agent` bucket. A `memory_search(run_id=X)` preview can therefore list rows that `memory_delete_all(run_id=X)` leaves in place. To clear rows written by several agents, delete them by id with `memory_delete_by_id`, or call `memory_delete_all` once per `agent_id` shown in the preview.
28
38
 
29
- ## No delete tools for RAG artifacts
39
+ ## Promoted memories are read-only through MCP
40
+
41
+ `memory_update` and `memory_delete_by_id` return `memory_is_promoted` for a memory that has been promoted to shared knowledge. Edit or remove promoted content in the Cloud UI Learnings tab.
42
+
43
+ ## No MCP tools for index / source / pipeline lifecycle
30
44
 
31
45
  There are no MCP tools to:
32
46
  - Delete a vector index
@@ -34,7 +48,7 @@ There are no MCP tools to:
34
48
  - Clear stuck work queue entries
35
49
  - Reset a failed pipeline
36
50
 
37
- KB-source deletion happens via the Meko control plane (REST: `DELETE /datapacks/:datapack_id/knowledge-bases`, or the UI), which removes the registration from the Meko API — but does **not** touch the actual `dist_rag` index, source records, or vector data in the datapack's database.
51
+ The one exception is a single uploaded **file**: `knowledgebase_delete_document` removes that file's chunks and metadata. KB-**source** deletion (the registered source, not one file) happens via the Meko control plane (REST: `DELETE /datapacks/:datapack_id/knowledge-bases`, or the UI): it unregisters the source from the Meko API but does **not** touch the actual `dist_rag` index, source records, or vector data in the datapack's database.
38
52
 
39
53
  **Workaround:** For stuck or failed indexes, create a new index with a different name. Stale indexes remain in the database until manually cleaned up by an admin.
40
54
 
@@ -70,8 +84,17 @@ It works **poorly** for:
70
84
 
71
85
  Never ingest CSV row-by-row into memory — each row becomes a fragmented fact with lost context.
72
86
 
73
- ## No semantic search over conversation content
87
+ ## Conversation search covers embedded turns only
88
+
89
+ `context_search` searches past conversation turns by meaning in its `conversation` bucket. Only turns embedded into the conversation-search cache are searchable. Turns are embedded by default, except when:
90
+
91
+ - the datapack opted out with `datapack_update(datapack_id=..., conversation_search_opt_out=True, conversation_id=...)`;
92
+ - the account hit the embedding quota (`conversation_search_skipped: "quota_exceeded"`); or
93
+ - the turn was too short to carry content (the server skips trivial turns); or
94
+ - the turn was stored before conversation search was enabled.
95
+
96
+ To find a conversation by other attributes, browse with `conversation_list` and inspect candidates with `conversation_get`.
74
97
 
75
- Semantic (meaning-based) search across stored conversation content is not part of the public tool surface today. To find a past conversation, browse with `conversation_list` (by datapack) and inspect candidates with `conversation_get`.
98
+ ## Very long conversations can't be read back
76
99
 
77
- For finding past knowledge by meaning, `memory_search` remains the most reliable path — which is why storing key facts via `memory_add` alongside conversations is important.
100
+ When a conversation's trace grows too large for Langfuse, `conversation_get` and `conversation_update` return `{"error": "not_found", "detail": "Conversation <id> not found"}` or time out for that conversation, even though `conversation_add_message` and `conversation_delete` still work. Servers without the MEKO-714 fix instead return `not_found` from `conversation_add_message` on these conversations. If read-back or a write fails with `not_found` on a long conversation that you know exists, report the failure as a server-side limit on that conversation. Don't recreate the conversation under the same id or replay its messages; that makes the trace larger.
@@ -26,22 +26,26 @@ memory_search(query="What plan does Alice have?", agent_id="support_bot")
26
26
  Conversations are backed by Langfuse sessions and traces. They preserve full structure: who said what, in what order, with what reasoning.
27
27
 
28
28
  ```
29
- conversation_create(agent_id="support_bot", title="Pricing discussion")
29
+ conversation_create(agent_id="support_bot", title="Pricing discussion",
30
+ datapack_id="<uuid from datapack_list>")
30
31
  -- Returns: {"id": "conv-uuid-here"}
31
32
 
32
33
  conversation_add_message(conversation_id="conv-uuid-here", agent_id="support_bot",
34
+ datapack_id="<uuid from datapack_list>",
33
35
  input="What are your pricing tiers?",
34
36
  output="We offer Starter ($10/mo), Pro ($50/mo), and Enterprise (custom).",
35
37
  reasoning="Retrieved pricing page data. No special discounts apply.")
36
38
  ```
37
39
 
40
+ `datapack_id` is required for both calls whenever no server-side default resolves for the caller. Omitting it in that state returns `{"error": "datapack_id_required"}` and persists nothing.
41
+
38
42
  ## Decision Matrix
39
43
 
40
44
  | Signal | Tool |
41
45
  |--------|------|
42
46
  | "remember that...", "note that...", "keep in mind..." | `memory_add` |
43
47
  | "store this conversation", "save this chat" | `conversation_create` + `conversation_add_message` |
44
- | "what do you know about X?", "recall..." | `memory_search` |
48
+ | "what do you know about X?", "recall..." | `context_search` |
45
49
  | "show me our past conversation about..." | `conversation_list` + `conversation_get` |
46
50
  | "the user prefers...", "their budget is..." | `memory_add` |
47
51
  | "save my query and your response" | `conversation_add_message` |
@@ -89,7 +93,7 @@ Agents on Cloud Meko have two distinct read surfaces. Pick the right one for the
89
93
 
90
94
  ### When the user asks "what do you know about X?"
91
95
 
92
- A full sweep is two calls: `memory_search` (all your personal memories, every agent — no per-agent fan-out) then `knowledgebase_search` (team-shared knowledge). When you answer, name which surface each finding came from, so the user knows why something is or isn't there.
96
+ Call `context_search`. One call returns your personal memories (every agent, no per-agent fan-out), team-shared knowledge, and matching past-conversation turns from anyone on the datapack. If the memory or KB bucket is empty, confirm with `memory_search` or `knowledgebase_search` before saying nothing is there, because `context_search` returns an empty list for a failed source. When you answer, name which surface each finding came from, so the user knows why something is or isn't there.
93
97
 
94
98
  ## Memory limitations for structured data
95
99
 
@@ -112,7 +116,7 @@ On Claude Code, do **not** proactively `memory_add` facts the user states — ca
112
116
 
113
117
  ## Automatic Conversation Capture
114
118
 
115
- The plugin captures conversations via three mechanisms — a periodic checkpoint (~10 min), a PreCompact hook, and a SessionEnd hook — storing the full transcript verbatim (user prompts as `input`, assistant text as `output`, tool calls and results as `reasoning`).
119
+ The plugin captures conversations via three mechanisms — a periodic checkpoint (~10 min), a PreCompact hook, and a SessionEnd hook — storing the full transcript verbatim (user prompts as `input`, assistant text as `output`, tool calls and results as `reasoning`). Skill bodies, background-task notifications, and subagent reports that Claude Code writes into the transcript go to `reasoning` of the turn they belong to, never to `input`. A typed `/skill args` is captured with that command as its `input`.
116
120
 
117
121
  Each message's seed is `<conversation_id>:<user_message_uuid>`; all three mechanisms derive the same deterministic trace ID from it, so overlapping captures are idempotent. A shared watermark file tracks what has been saved.
118
122