@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
@@ -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="claude_desktop",
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 call. For Claude Desktop that's `claude_desktop` for normal attribution, or `meko_agent` when writing genuinely cross-project facts. Writes retain that attribution, while personal memory reads span all of this user's agents.
@@ -16,6 +57,7 @@ Every tool example below shows the correct parameters, expected response, and co
16
57
 
17
58
  ```
18
59
  memory_add(agent_id="claude_desktop",
60
+ conversation_id="<id from conversation_create>",
19
61
  text="Remember: deploy scripts must be run from the repo root, never a subdir.")
20
62
  ```
21
63
 
@@ -24,12 +66,6 @@ memory_add(agent_id="claude_desktop",
24
66
  {"results": [{"id": "mem-uuid-123", "memory": "User Amiram is VP of Product at YugabyteDB. Prefers concise responses."}]}
25
67
  ```
26
68
 
27
- **With user scoping:**
28
- ```
29
- memory_add(agent_id="agent", user_id="amiram",
30
- text="Prefers Python for backend, Go for infrastructure.")
31
- ```
32
-
33
69
  **What NOT to store via memory_add:**
34
70
  - Full conversations (use `conversation_create` + `conversation_add_message`)
35
71
  - Large documents (use the UI's Datapack → Actions → Add Knowledge upload flow)
@@ -46,35 +82,32 @@ memory_add(agent_id="agent", user_id="amiram",
46
82
 
47
83
  **Cross-conversation discovery.** `memory_search` returns hits across every stored conversation for the `(datapack_id, user_id)` pair, across all agents (the tool intentionally passes `meko_agent_id=None` to mem0, so the `agent_id` argument scopes the trace but does not filter 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. Pass `run_id` on the search itself to narrow to a single conversation up front.
48
84
 
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.
85
+ **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
86
 
51
87
  ```
52
- memory_search(query="What programming language does the team use?", agent_id="agent")
88
+ memory_search(query="What programming language does the team use?", agent_id="claude_desktop", conversation_id="<id>")
53
89
  ```
54
90
 
55
91
  **Response:**
56
92
  ```json
57
- {"results": [{"id": "mem-uuid-123", "memory": "Team uses Python for backend", "score": 0.89}]}
93
+ {"results": [{"id": "mem-uuid-123", "memory": "Team uses Python for backend", "score": 0.89, "raw_similarity_score": 0.72}]}
58
94
  ```
59
95
 
96
+ `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.
97
+
60
98
  **With limit:**
61
99
  ```
62
- memory_search(query="user preferences", agent_id="agent", limit=5)
100
+ memory_search(query="user preferences", agent_id="claude_desktop", conversation_id="<id>", limit=5)
63
101
  ```
64
102
 
65
103
  ---
66
104
 
67
105
  ### memory_get_all
68
106
 
69
- **When to use:** List everything stored for an agent. Useful at session start to load context.
107
+ **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.
70
108
 
71
109
  ```
72
- memory_get_all(agent_id="agent")
73
- ```
74
-
75
- **With user scoping:**
76
- ```
77
- memory_get_all(agent_id="agent", user_id="amiram")
110
+ memory_get_all(agent_id="claude_desktop", conversation_id="<id>")
78
111
  ```
79
112
 
80
113
  ---
@@ -82,7 +115,7 @@ memory_get_all(agent_id="agent", user_id="amiram")
82
115
  ### memory_get_by_id
83
116
 
84
117
  ```
85
- memory_get_by_id(memory_id="mem-uuid-123", agent_id="agent")
118
+ memory_get_by_id(memory_id="mem-uuid-123", agent_id="claude_desktop", conversation_id="<id>")
86
119
  ```
87
120
 
88
121
  ---
@@ -92,7 +125,7 @@ memory_get_by_id(memory_id="mem-uuid-123", agent_id="agent")
92
125
  **When to use:** Overwrite a specific memory's text. Requires the memory UUID.
93
126
 
94
127
  ```
95
- memory_update(memory_id="mem-uuid-123", text="Updated: Team uses Go for all new services", agent_id="agent")
128
+ memory_update(memory_id="mem-uuid-123", text="Updated: Team uses Go for all new services", agent_id="claude_desktop", conversation_id="<id>")
96
129
  ```
97
130
 
98
131
  ---
@@ -100,17 +133,19 @@ memory_update(memory_id="mem-uuid-123", text="Updated: Team uses Go for all new
100
133
  ### memory_delete_by_id
101
134
 
102
135
  ```
103
- memory_delete_by_id(memory_id="mem-uuid-123", agent_id="agent")
136
+ memory_delete_by_id(memory_id="mem-uuid-123", agent_id="claude_desktop", conversation_id="<id>")
104
137
  ```
105
138
 
139
+ `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.
140
+
106
141
  ---
107
142
 
108
143
  ### memory_delete_all
109
144
 
110
- **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.
145
+ **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`.
111
146
 
112
147
  ```
113
- memory_delete_all(agent_id="agent")
148
+ memory_delete_all(agent_id="claude_desktop", conversation_id="<id>")
114
149
  ```
115
150
 
116
151
  ---
@@ -142,10 +177,13 @@ On 403, authentication, or permission failure, report the error and stop — do
142
177
  **When to use:** Start storing a multi-turn exchange. Do this when the session contains valuable dialog worth preserving.
143
178
 
144
179
  ```
145
- conversation_create(agent_id="agent", user_id="amiram",
146
- title="Debugging the auth middleware")
180
+ conversation_create(agent_id="claude_desktop",
181
+ title="Debugging the auth middleware",
182
+ datapack_id="<uuid from datapack_list>")
147
183
  ```
148
184
 
185
+ `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`.
186
+
149
187
  **Response:**
150
188
  ```json
151
189
  {"id": "conv-uuid-123", "title": "Debugging the auth middleware"}
@@ -216,7 +254,7 @@ conversation_delete(conversation_id="conv-uuid-123", agent_id="agent")
216
254
 
217
255
  ## Knowledge Base Tools
218
256
 
219
- **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.
257
+ **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.
220
258
 
221
259
  See `tools-rag-workflow.md` for the decision table.
222
260
 
@@ -244,6 +282,17 @@ Populated KBs return results with chunk content and similarity scores. An empty/
244
282
 
245
283
  ---
246
284
 
285
+ ### knowledgebase_delete_document
286
+
287
+ 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.
288
+
289
+ ```
290
+ knowledgebase_delete_document(document_id="<uuid from a search hit>",
291
+ conversation_id="<session conversation id>")
292
+ ```
293
+
294
+ 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.
295
+
247
296
  ## Artifact Tools
248
297
 
249
298
  ### artifact_put
@@ -326,21 +375,34 @@ For large files use `local_path` to read the file. S3 URLs are never exposed.
326
375
  ### datapack_create / datapack_list / datapack_describe
327
376
 
328
377
  ```
329
- datapack_create(name="analytics_prod")
378
+ datapack_create(name="analytics_prod", conversation_id="<conversation id>")
330
379
  datapack_list(conversation_id="<this conversation's id>") # returns datapack_id for each datapack
331
- datapack_describe(datapack_id="<uuid>", include_status=True)
380
+ datapack_describe(datapack_id="<uuid>", include_status=True, conversation_id="<conversation id>")
332
381
  ```
333
382
 
383
+ `datapack_describe` returns these counts:
384
+
385
+ | Field | Meaning |
386
+ |---|---|
387
+ | `memory_count` | All memories stored in the datapack |
388
+ | `collective_memory_count` | Memories promoted to shared knowledge |
389
+ | `learnings_count` | Memories awaiting a promotion decision |
390
+ | `knowledge_base_file_count` | Uploaded KB documents; `null` if the status endpoint is unreachable |
391
+ | `knowledge_chunk_count` | KB chunks across all documents (for debugging retrieval) |
392
+ | `shared_knowledge_count` | `collective_memory_count + knowledge_base_file_count`; `null` when the file count is `null` |
393
+
394
+ `knowledge_count` is a deprecated alias of `knowledge_chunk_count`. `datapack_list` doesn't compute counts; call `datapack_describe` for them.
395
+
334
396
  ### datapack_update / datapack_delete
335
397
 
336
398
  `datapack_update` renames a datapack, edits its description, and/or opts it in/out of conversation-search embedding. At least one of `name` / `description` / `conversation_search_opt_out` must be provided (or the tool returns `nothing_to_update`). The server refuses to rename `meko_default_datapack` — the error is `"meko_default_datapack cannot be renamed"`. Passing `description=""` does NOT clear an existing description. `conversation_search_opt_out=True` stops future turns from being indexed 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.
337
399
 
338
400
  ```
339
- datapack_update(datapack_id="<uuid>", name="renamed-datapack")
340
- datapack_update(datapack_id="<uuid>", description="new description")
341
- datapack_update(datapack_id="<uuid>", name="x", description="y")
342
- datapack_update(datapack_id="<uuid>", conversation_search_opt_out=True)
343
- datapack_delete(datapack_id="<uuid>") # Irreversible!
401
+ datapack_update(datapack_id="<uuid>", name="renamed-datapack", conversation_id="<conversation id>")
402
+ datapack_update(datapack_id="<uuid>", description="new description", conversation_id="<conversation id>")
403
+ datapack_update(datapack_id="<uuid>", name="x", description="y", conversation_id="<conversation id>")
404
+ datapack_update(datapack_id="<uuid>", conversation_search_opt_out=True, conversation_id="<conversation id>")
405
+ datapack_delete(datapack_id="<uuid>", conversation_id="<conversation id>") # Irreversible!
344
406
  ```
345
407
 
346
408
  ### Agent and knowledge-base management (NOT MCP — control-plane only)
@@ -350,4 +412,4 @@ Agent and KB lifecycle does not ship as MCP tools. If the user asks to create/li
350
412
  - REST: `POST/GET/DELETE /datapacks/:datapack_id/agents` (agents), `POST/GET/DELETE /datapacks/:datapack_id/knowledge-bases` (KB sources).
351
413
  - Or the Meko Cloud UI at `cloud.mekodata.ai` → Datapacks → agents / knowledge-bases.
352
414
 
353
- 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`.
415
+ 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`.
@@ -2,7 +2,7 @@
2
2
 
3
3
  These are current limitations of the Meko MCP tools. Know them upfront to avoid wasted tool calls.
4
4
 
5
- ## No delete tools for RAG artifacts
5
+ ## No MCP tools for index / source / pipeline lifecycle
6
6
 
7
7
  There are no MCP tools to:
8
8
  - Delete a vector index
@@ -10,7 +10,7 @@ There are no MCP tools to:
10
10
  - Clear stuck work queue entries
11
11
  - Reset a failed pipeline
12
12
 
13
- 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.
13
+ 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.
14
14
 
15
15
  **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.
16
16
 
@@ -56,8 +56,25 @@ The skill description is tuned to its 1024-char ceiling; broadening it further d
56
56
  2. **Server-side guidance** — the `agent_id` tool docstrings and the server's connect-time instructions name `claude_desktop` as this client's bucket, so even a skill-less tool-search call avoids the wrong-bucket (`claude_code`) write.
57
57
  3. Nothing is lost when the *user* explicitly recalls or saves — only passive capture of in-passing facts is best-effort.
58
58
 
59
- ## No semantic search over conversation content
59
+ ## memory_delete_all is agent-scoped; memory reads are not
60
60
 
61
- 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`.
61
+ `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.
62
62
 
63
- 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.
63
+ ## Promoted memories are read-only through MCP
64
+
65
+ `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.
66
+
67
+ ## Conversation search covers embedded turns only
68
+
69
+ `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:
70
+
71
+ - the datapack opted out with `datapack_update(datapack_id=..., conversation_search_opt_out=True, conversation_id=...)`;
72
+ - the account hit the embedding quota (`conversation_search_skipped: "quota_exceeded"`); or
73
+ - the turn was too short to carry content (the server skips trivial turns); or
74
+ - the turn was stored before conversation search was enabled.
75
+
76
+ To find a conversation by other attributes, browse with `conversation_list` and inspect candidates with `conversation_get`.
77
+
78
+ ## Very long conversations can't be read back
79
+
80
+ 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.
@@ -11,10 +11,10 @@
11
11
  Memory is backed by pgvector. Search is hybrid: semantic similarity, keyword matching, and a boost for memories that mention the entities named in your query (people, projects, tools). It retrieves relevant facts by meaning, not by conversation order.
12
12
 
13
13
  ```
14
- memory_add(agent_id="support_bot",
15
- text="Customer Alice (alice@acme.com) prefers email, has Pro plan.", user_id="alice_123")
14
+ memory_add(agent_id="claude_desktop", conversation_id="<id>",
15
+ text="Customer Alice (alice@acme.com) prefers email, has Pro plan.")
16
16
 
17
- memory_search(query="What plan does Alice have?", agent_id="support_bot")
17
+ memory_search(query="What plan does Alice have?", agent_id="claude_desktop", conversation_id="<id>")
18
18
  ```
19
19
 
20
20
  ## Use `conversation_create` + `conversation_add_message` when storing:
@@ -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", user_id="alice_123", title="Pricing discussion")
29
+ conversation_create(agent_id="claude_desktop", title="Pricing discussion",
30
+ datapack_id="<uuid from datapack_list>")
30
31
  -- Returns: {"id": "conv-uuid-here"}
31
32
 
32
- conversation_add_message(conversation_id="conv-uuid-here", agent_id="support_bot",
33
+ conversation_add_message(conversation_id="conv-uuid-here", agent_id="claude_desktop",
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,14 +93,13 @@ One `memory_search` already spans this user's memories across all agents; no per
89
93
 
90
94
  ### When the user asks "what do you know about X?"
91
95
 
92
- A full sweep is two calls (budget for it — each is 2-6 seconds):
96
+ Call `context_search`:
93
97
 
94
98
  ```
95
- memory_search(agent_id="claude_desktop", query="X", conversation_id=..., ...)
96
- knowledgebase_search(agent_id="<anything>", datapack_id="<uuid>", query="X", conversation_id=..., ...)
99
+ context_search(agent_id="claude_desktop", query="X", conversation_id=..., datapack_id="<uuid>")
97
100
  ```
98
101
 
99
- The single `memory_search` includes everything this user and their other agents wrote in the datapack.
102
+ Its memory bucket includes everything this user and their other agents wrote in the datapack. The KB bucket holds team-shared knowledge, and the conversation bucket holds matching past 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.
100
103
 
101
104
  When you answer, be explicit about scope so the user knows why something is or isn't there:
102
105
 
@@ -146,6 +149,7 @@ The full transcript including:
146
149
  - **Assistant responses** — all text blocks (the `output` field)
147
150
  - **Tool calls** — tool name + input parameters (the `reasoning` field)
148
151
  - **Tool results** — output from tool executions (appended to `reasoning`)
152
+ - **Injected context** — skill bodies, background-task notifications, and subagent reports that the client writes into the transcript (appended to `reasoning` of the turn they belong to, never used as `input`)
149
153
 
150
154
  This is more than just text — tool calls and results are critical context for session replay, cross-agent sharing, and compaction.
151
155
 
@@ -1,22 +1,23 @@
1
1
  # Complete Tool Catalog and Decision Tree
2
2
 
3
- **23 Meko data tools covered by this skill.** These are the tools available in production, grouped as: Memory (8), Conversation (6), Knowledge Base (1), Datapack (5), Artifacts (2), Observability (1). Combined Meko + AMP endpoints may expose additional infrastructure tools; those are outside this skill's scope.
3
+ **25 Meko data tools covered by this skill.** These are the tools available in production, grouped as: Retrieval (1), Memory (8), Conversation (6), Knowledge Base (2), Datapack (5), Artifacts (2), Observability (1). Combined Meko + AMP endpoints may expose additional infrastructure tools; those are outside this skill's scope.
4
4
 
5
5
  ## Quick health check before using tools
6
6
 
7
7
  Before starting a session, verify that the Meko MCP tools are working:
8
8
 
9
- 1. `memory_search(query="test", agent_id="<your-session-agent-id>", conversation_id="<session-conversation-id>")` — Confirms memory subsystem is up. Use the `agent_id` and `conversation_id` from the SessionStart `additionalContext`. May fail with "connection already closed" — see `tools-troubleshooting.md`.
9
+ 1. `memory_search(query="test", agent_id="claude_desktop", conversation_id="<id from conversation_create>")` — Confirms memory subsystem is up. May fail with "connection already closed" — see `tools-troubleshooting.md`.
10
10
  2. `datapack_list(conversation_id="<this conversation's id>")` — Confirms Meko API connectivity. Returns the datapacks your token has access to.
11
11
 
12
12
  ## Decision tree: which tool do I need?
13
13
 
14
14
  ```
15
15
  User wants to...
16
+ ├── Ask "what do you know about X?" --------> context_search (read; memory + KB + past conversations in one call)
16
17
  ├── Search personal context? ---------------> memory_search (read)
17
18
  ├── Search shared datapack knowledge? ------> knowledgebase_search (read)
18
19
  ├── Add documents to a knowledge base? -----> point user at Meko UI: Datapack → Actions → Add Knowledge
19
- │ (no MCP tool — Cloud uses UI ingestion only)
20
+ ├── Delete ONE knowledge-base file? --------> knowledgebase_delete_document (destructive — confirm with the user first)
20
21
  ├── Store or recall information?
21
22
  │ ├── Store a fact/preference/entity? -----------> memory_add (write)
22
23
  │ ├── Store a full conversation (multi-turn)? ---> conversation_create + conversation_add_message (write)
@@ -30,47 +31,56 @@ User wants to...
30
31
  └── CRUD datapack? --------------------> datapack_create/list/describe/update/delete
31
32
  ```
32
33
 
33
- Agent / knowledge-base lifecycle is managed **outside** the MCP surface — typically in the Meko control-plane UI — and is not exposed as tools here.
34
+ Agent lifecycle and KB **ingestion / index lifecycle** (adding sources, uploads, re-indexing) are managed outside the MCP surface — typically in the Meko control-plane UI. Deleting a single KB file IS exposed here (`knowledgebase_delete_document`).
34
35
 
35
- ## Knowledge Base Tools (1)
36
+ ## Retrieval Tools (1)
36
37
 
37
38
  | Tool | Purpose |
38
39
  |------|---------|
39
- | `knowledgebase_search(query, agent_id, conversation_id, datapack_id, limit=10)` | Semantic search across KB chunks. `datapack_id` is REQUIRED (no default). |
40
+ | `context_search(query, conversation_id, agent_id=None, datapack_id=None, limit=10, force_source="auto")` | Default first call for open-ended recall. Queries memory, the knowledge base, and the conversation-history cache in parallel and returns each source in its own bucket: `{"results": {"memory": [...], "knowledge_base": [...], "conversation": {"hits": [...], "thread": [...]}}, "token_savings": {...}}`. 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. 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. `force_source` is `"auto"` (all three), `"memory"`, `"knowledge_base"`, or `"conversation"`; any other value returns `invalid_force_source`. `limit` bounds the memory and KB buckets only; the conversation bucket returns up to 10 hits plus a thread of whole turns. 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
+
42
+ ## Knowledge Base Tools (2)
43
+
44
+ | Tool | Purpose |
45
+ |------|---------|
46
+ | `knowledgebase_search(query, conversation_id, datapack_id, agent_id=None, limit=10)` | Hybrid (semantic + keyword) search across KB chunks and promoted memories. `datapack_id` is REQUIRED (no default). Each hit has `id`, `chunk_text`, `document_id`, `metadata_filters`, `distance`, and `match_type` (`semantic`, `keyword`, or `hybrid`). |
47
+ | `knowledgebase_delete_document(document_id, conversation_id, datapack_id="")` | Permanently delete ONE KB file (chunks + metadata; stored-file delete is best-effort — check `s3_deleted`). Irreversible: confirm with the user first. `document_id` comes from `knowledgebase_search` hits (no filename in hits — echo the id + chunk text). Owner/maintainer/uploader only (status 403 otherwise); status 409 while still indexing — wait and retry. |
40
48
 
41
49
  ## Memory Tools (8)
42
50
 
43
51
  | Tool | Purpose |
44
52
  |------|---------|
45
- | `memory_add(text, agent_id, conversation_id, user_id=None, app_id=None, run_id=None, metadata=None, messages=None, datapack_id=None)` | Store fact/preference/entity as long-term memory |
46
- | `memory_search(query, agent_id, conversation_id="", user_id=None, limit=10, datapack_id=None)` | Hybrid search across memories (semantic + keyword + entity boost). `conversation_id` optional (omit or pass `""` for cross-conversation discovery). |
47
- | `memory_get_by_id(memory_id, agent_id, conversation_id, datapack_id=None)` | Direct pgvector row lookup by UUID. Preferred over `memory_search` for exact-id verification. |
48
- | `memory_get_all(agent_id, conversation_id, user_id=None, app_id=None, run_id=None, datapack_id=None)` | List all memories for agent |
49
- | `memory_update(memory_id, text, agent_id, conversation_id, datapack_id=None)` | Overwrite memory text |
50
- | `memory_delete_by_id(memory_id, agent_id, conversation_id, datapack_id=None)` | Delete a single memory |
51
- | `memory_delete_all(agent_id, conversation_id, user_id=None, app_id=None, run_id=None, datapack_id=None)` | Delete all memories for agent (destructive) |
52
- | `memory_promote(conversation_id, memory_ids, agent_id=None, datapack_id=None)` | Promote private memories into the datapack's shared knowledge base (moves them out of mem0, then evicts from mem0 — one-way). Owners/maintainers only; viewers/contributors get 403.
53
+ | `memory_add(text, conversation_id, agent_id=None, run_id=None, metadata=None, messages=None, datapack_id=None)` | Store fact/preference/entity as long-term memory |
54
+ | `memory_search(query, conversation_id, agent_id=None, limit=10, datapack_id=None, run_id=None)` | Hybrid search across memories (semantic + keyword + entity boost). Drops rows below a server-configured similarity floor (default 0.2), so a weak query can return an empty list. `conversation_id` is required but only nests the trace. It must be a 32-hex id: `""` currently fails (MEKO-707), so pass a freshly generated one if you have no conversation yet. `run_id` filters to one conversation's memories. |
55
+ | `memory_get_by_id(memory_id, conversation_id, agent_id=None, datapack_id=None)` | Direct pgvector row lookup by UUID. Preferred over `memory_search` for exact-id verification. Returns `not_found` for a missing id and for an id that belongs to another account. |
56
+ | `memory_get_all(conversation_id, agent_id=None, run_id=None, datapack_id=None, promoted=False)` | Recent window (about 20 rows) of the user's memories across every agent, plus the true `total`. Not a complete listing. `promoted=True` returns the recent window of promoted memories instead. `run_id` is ignored. |
57
+ | `memory_update(memory_id, text, conversation_id, agent_id=None, datapack_id=None)` | Overwrite memory text. Returns `memory_is_promoted` for a promoted memory (edit those in the Cloud UI Learnings tab). |
58
+ | `memory_delete_by_id(memory_id, conversation_id, agent_id=None, datapack_id=None)` | Delete a single memory. Returns `memory_is_promoted` for a promoted memory. |
59
+ | `memory_delete_all(conversation_id, agent_id=None, run_id=None, datapack_id=None)` | Delete all memories in the **passed `agent_id`'s bucket** (destructive). Unlike reads, this is agent-scoped: omitting `agent_id` deletes only the `meko_agent` bucket. `run_id` narrows it to one conversation; a malformed value returns `invalid_run_id`. |
60
+ | `memory_promote(conversation_id, memory_ids, agent_id=None, datapack_id=None)` | Promote private memories into the datapack's shared knowledge base (moves them out of mem0, then evicts from mem0 — one-way). Owners/maintainers only; viewers/contributors get 403. |
53
61
 
54
62
  ## Conversation Tools (6)
55
63
 
56
64
  | Tool | Purpose |
57
65
  |------|---------|
58
- | `conversation_create(agent_id, user_id=None, app_id=None, run_id=None, title=None, metadata=None, session_id="")` | Create conversation container (Langfuse session) |
59
- | `conversation_add_message(conversation_id, agent_id, input, output=None, reasoning=None, metadata=None, seed=None, trace_id="")` | Add a message turn (Langfuse trace) |
60
- | `conversation_get(conversation_id, agent_id, include_messages=False, limit=100, offset=0)` | Retrieve conversation, optionally with messages |
61
- | `conversation_list(agent_id=None, limit=20, offset=0, conversation_id="", datapack_id=None)` | List conversations for agent within a datapack. `datapack_id` (UUID) is optional — defaults to the pinned/tenant datapack; use `datapack_list` to look it up. `conversation_id` optional (omit for browse). |
62
- | `conversation_update(conversation_id, agent_id, title=None, metadata=None)` | Update title or metadata |
63
- | `conversation_delete(conversation_id, agent_id)` | Delete entire conversation (destructive) |
66
+ | `conversation_create(agent_id=None, run_id=None, title=None, metadata=None, session_id="", datapack_id=None)` | Create conversation container (Langfuse session) |
67
+ | `conversation_add_message(conversation_id, input, output, agent_id=None, reasoning=None, metadata=None, seed=None, datapack_id=None, plan=None)` | Add a message turn (Langfuse trace). `output` is required. The response may include `extracted_memories` and, when the turn wasn't embedded for conversation search, `conversation_search_skipped` (`quota_exceeded` or `datapack_opted_out`). |
68
+ | `conversation_get(conversation_id, agent_id=None, include_messages=False, limit=100, offset=0, datapack_id=None)` | Retrieve conversation, optionally with messages |
69
+ | `conversation_list(agent_id=None, limit=20, offset=0, conversation_id="", datapack_id=None)` | List the user's conversations within a datapack (`agent_id` does not filter — trace attribution only). `datapack_id` (UUID) is optional — defaults to the pinned/tenant datapack; use `datapack_list` to look it up. `conversation_id` optional (omit for browse). |
70
+ | `conversation_update(conversation_id, agent_id=None, title=None, metadata=None, datapack_id=None)` | Update title or metadata |
71
+ | `conversation_delete(conversation_id, agent_id=None, datapack_id=None)` | Delete entire conversation (destructive) |
64
72
 
65
73
  ## Datapack Management Tools (5)
66
74
 
67
75
  | Tool | Purpose |
68
76
  |------|---------|
69
- | `datapack_create(name)` | Create new datapack |
77
+ | `datapack_create(name, conversation_id)` | Create new datapack |
70
78
  | `datapack_list(conversation_id, datapack_id=None)` | List all datapacks. `conversation_id` is required for trace nesting; omit `datapack_id` to use the endpoint default. |
71
- | `datapack_describe(datapack_id, include_status=False)` | Describe datapack by UUID |
72
- | `datapack_update(datapack_id, name=None, description=None)` | Rename a datapack and/or update its description. Pass at least one of `name` / `description`. |
73
- | `datapack_delete(datapack_id)` | Delete datapack by UUID (irreversible) |
79
+ | `datapack_describe(conversation_id, datapack_id="", include_status=False)` | Describe a datapack by UUID (default datapack if omitted). Returns `memory_count`, `collective_memory_count` (promoted), `learnings_count` (awaiting a promotion decision), `knowledge_base_file_count`, `knowledge_chunk_count`, and `shared_knowledge_count`. `knowledge_base_file_count` and `shared_knowledge_count` are `null` when the status endpoint is unreachable; `knowledge_count` is a deprecated alias of `knowledge_chunk_count`. |
80
+ | `datapack_update(datapack_id, conversation_id, name=None, description=None, conversation_search_opt_out=None)` | Rename a datapack, update its description, and/or opt out of (or back into) conversation-search caching. Pass at least one field. Opt-out is owner/maintainer only. |
81
+ | `datapack_delete(datapack_id, conversation_id)` | Delete datapack by UUID (irreversible) |
82
+
83
+ All five datapack tools reject an empty `conversation_id` with `conversation_id_required`.
74
84
 
75
85
  ## Artifact Tools (2)
76
86
 
@@ -104,4 +114,4 @@ For knowledge-base content on Cloud, the canonical path is **UI upload**: Datapa
104
114
 
105
115
  ## Common Parameter Patterns
106
116
 
107
- Memory and KB tools accept optional `datapack_id` to target a specific datapack. Memory and conversation tools require `agent_id` for namespace isolation (see `tools-agent-id-conventions.md`).
117
+ Memory and KB tools accept optional `datapack_id` to target a specific datapack. A `datapack_id` your account can't access returns `datapack_access_denied`. `agent_id` attributes writes. Conversations are agent-owned: `conversation_get`, `conversation_add_message`, `conversation_update`, and `conversation_delete` return `agent_id_mismatch` for any value other than the creating agent's. `agent_id` does **not** filter memory reads (`memory_search`/`memory_get_all`) or `conversation_list`, which return all your agents' rows for the user. `memory_delete_all` is the exception on the memory side: it deletes only the passed `agent_id`'s bucket. See `tools-agent-id-conventions.md`.
@@ -1,6 +1,7 @@
1
1
  # Knowledge Base / RAG workflow
2
2
 
3
- `knowledgebase_search` is the only KB tool exposed via MCP. Index
3
+ MCP exposes two KB tools: `knowledgebase_search` (retrieval) and
4
+ `knowledgebase_delete_document` (remove ONE uploaded file). Index
4
5
  creation and ingestion happen out of band — through the **Meko UI**
5
6
  (`cloud.mekodata.ai`).
6
7
 
@@ -8,9 +9,10 @@ creation and ingestion happen out of band — through the **Meko UI**
8
9
 
9
10
  | Situation | Use this | Why |
10
11
  |---|---|---|
11
- | Search an existing KB | `knowledgebase_search` | The one KB tool exposed via MCP |
12
+ | Search an existing KB | `knowledgebase_search` | Retrieval over the indexed chunks |
12
13
  | Add documents to a KB | **Meko UI** — Datapack → Actions → **Add Knowledge** | File-upload dialog (PDF/TXT/MD/JSON/MP4, 5 MB each, 10/batch). No MCP equivalent |
13
- | Anything else (list / delete / rename / re-index) | **UI** | No MCP tools for KB lifecycle |
14
+ | Delete ONE uploaded file | `knowledgebase_delete_document` | Destructive; `document_id` from search hits; confirm with the user first |
15
+ | Anything else (list / rename / re-index / source lifecycle) | **UI** | No MCP tools for the rest of KB lifecycle |
14
16
 
15
17
  ## knowledgebase_search — the one you'll actually call
16
18
 
@@ -23,7 +25,7 @@ knowledgebase_search(
23
25
  limit=10)
24
26
  ```
25
27
 
26
- Required: `query`, `agent_id`, `conversation_id`, `datapack_id`.
28
+ Required: `query`, `conversation_id`, `datapack_id`.
27
29
  Unlike the memory tools, `datapack_id` has no default here — you must
28
30
  pass it explicitly. `agent_id` is **ignored for filtering** on this
29
31
  tool (KB results are team-shared on the datapack), but you still pass
@@ -37,10 +39,12 @@ Populated KB:
37
39
  {
38
40
  "results": [
39
41
  {
40
- "content": "<chunk text>",
41
- "similarity": 0.87,
42
- "source_uri": "<original source URI>",
43
- "document_name": "<file key>",
42
+ "id": "<chunk id>",
43
+ "chunk_text": "<chunk text>",
44
+ "document_id": "<KB document id; pass to knowledgebase_delete_document>",
45
+ "metadata_filters": {},
46
+ "distance": 0.31,
47
+ "match_type": "semantic" | "keyword" | "hybrid",
44
48
  ...
45
49
  },
46
50
  ...
@@ -49,6 +53,8 @@ Populated KB:
49
53
  }
50
54
  ```
51
55
 
56
+ Lower `distance` is closer. Promoted memories appear as hits whose `metadata_filters.source` is `"memory"`. Hits carry no filename, so show the user the `document_id` and chunk text when they need to identify a file.
57
+
52
58
  Empty or nonexistent KB: `{"results": [], "count": 0}` (no error,
53
59
  just an empty array).
54
60