@yugabytedb/meko-mcp 2.0.0 → 2.1.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 (48) hide show
  1. package/README.md +31 -6
  2. package/assets/hooks-handlers/codex-session-end.sh +78 -0
  3. package/assets/hooks-handlers/lib/capture.js +163 -14
  4. package/assets/hooks-handlers/lib/checkpoint-timer.js +44 -2
  5. package/assets/hooks-handlers/session-end.sh +10 -0
  6. package/assets/hooks-handlers/session-start.sh +8 -1
  7. package/assets/hooks-handlers/test_checkpoint_timer.sh +162 -0
  8. package/assets/scripts/package-desktop-skill.sh +32 -1
  9. package/assets/skills/meko-mcp-tools/SKILL.md +47 -41
  10. package/assets/skills/meko-mcp-tools/references/_sections.md +2 -4
  11. package/assets/skills/meko-mcp-tools/references/tools-agent-id-conventions.md +29 -25
  12. package/assets/skills/meko-mcp-tools/references/tools-conversation-dedup.md +5 -7
  13. package/assets/skills/meko-mcp-tools/references/tools-conversation-reasoning.md +50 -0
  14. package/assets/skills/meko-mcp-tools/references/tools-cookbook.md +63 -46
  15. package/assets/skills/meko-mcp-tools/references/tools-datapack-workflow.md +6 -6
  16. package/assets/skills/meko-mcp-tools/references/tools-known-limitations.md +4 -4
  17. package/assets/skills/meko-mcp-tools/references/tools-memory-vs-conversation.md +17 -22
  18. package/assets/skills/meko-mcp-tools/references/tools-overview.md +40 -39
  19. package/assets/skills/meko-mcp-tools/references/tools-rag-workflow.md +1 -2
  20. package/assets/skills/meko-mcp-tools/references/tools-troubleshooting.md +4 -18
  21. package/assets/skills/meko-mcp-tools/references/tools-user-id-conventions.md +9 -8
  22. package/assets/skills/meko-mcp-tools-desktop/SKILL.md +49 -42
  23. package/assets/skills/meko-mcp-tools-desktop/desktop/README.md +6 -6
  24. package/assets/skills/meko-mcp-tools-desktop/references/_sections.md +2 -2
  25. package/assets/skills/meko-mcp-tools-desktop/references/tools-agent-id-conventions.md +28 -24
  26. package/assets/skills/meko-mcp-tools-desktop/references/tools-conversation-reasoning.md +50 -0
  27. package/assets/skills/meko-mcp-tools-desktop/references/tools-cookbook.md +61 -36
  28. package/assets/skills/meko-mcp-tools-desktop/references/tools-known-limitations.md +4 -4
  29. package/assets/skills/meko-mcp-tools-desktop/references/tools-memory-vs-conversation.md +16 -19
  30. package/assets/skills/meko-mcp-tools-desktop/references/tools-overview.md +40 -39
  31. package/assets/skills/meko-mcp-tools-desktop/references/tools-rag-workflow.md +1 -2
  32. package/assets/skills/meko-mcp-tools-desktop/references/tools-troubleshooting.md +3 -17
  33. package/assets/skills/meko-select-datapack-desktop/SKILL.md +31 -21
  34. package/assets/skills/meko-select-datapack-desktop/references/cookbook.md +8 -8
  35. package/assets/skills/meko-select-datapack-desktop/references/role-display-future.md +41 -0
  36. package/assets/skills/meko-select-datapack-desktop/references/troubleshooting.md +1 -1
  37. package/bin/create-meko-setup.mjs +45 -6
  38. package/lib/clients/claude-code.mjs +8 -4
  39. package/lib/clients/claude-desktop.mjs +14 -0
  40. package/lib/clients/codex.mjs +23 -8
  41. package/lib/clients/common.mjs +2 -0
  42. package/lib/clients/cursor.mjs +7 -2
  43. package/lib/detect.mjs +7 -2
  44. package/lib/prompt.mjs +1 -1
  45. package/lib/url-selection.mjs +55 -0
  46. package/package.json +1 -1
  47. package/assets/skills/meko-mcp-tools/references/tools-scope-permissions.md +0 -71
  48. package/assets/skills/meko-mcp-tools-desktop/references/tools-scope-permissions.md +0 -71
@@ -1,12 +1,12 @@
1
1
  # agent_id — multi-agent identity on Cloud Meko
2
2
 
3
- `agent_id` identifies **which agent wrote a memory or created a conversation**. It is not a constant. Pick a value that represents the specific agent + project you're acting for, use it consistently for writes within this session, and use it to scope your own reads.
3
+ `agent_id` identifies **which agent wrote a memory or created a conversation**. It is not a constant. Pick a value that represents the client you're acting for and use it consistently for writes and trace attribution within this session.
4
4
 
5
- The Cloud UI (`cloud.mekodata.ai`) renders `agent_id` as a badge on every memory and conversation row — so the value you pick is user-visible. Multiple different agents with different `agent_id` values can write into the same datapack; each one's personal view is scoped to itself, and the UI shows the full cross-agent picture.
5
+ The Cloud UI (`cloud.mekodata.ai`) renders `agent_id` as a badge on every memory and conversation row — so the value you pick is user-visible. Multiple different agents can write into the same datapack, and both the UI and one `memory_search` show the user's full cross-agent picture.
6
6
 
7
7
  ## The three buckets
8
8
 
9
- Memories segregate strictly by `agent_id`. Pick the right bucket up front:
9
+ Each memory is tagged with the writing `agent_id`. Pick the right value up front so attribution remains meaningful:
10
10
 
11
11
  | Pattern | When to use | Example |
12
12
  |---|---|---|
@@ -14,13 +14,15 @@ Memories segregate strictly by `agent_id`. Pick the right bucket up front:
14
14
  | `<client>:<repo-basename>` | Coding agents (Claude Code, Cursor) writing project-scoped facts. **Not used by Claude Desktop**, but you'll see these values on rows written by other clients in the same datapack. | `claude_code:meko-mcp-server` |
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
- **For Claude Desktop, the practical default is `claude_desktop` for personal context and `meko_agent` for genuinely cross-client facts.** When the user's information is project-agnostic ("the user is named Amiram", "the user prefers vim"), prefer `meko_agent` so other clients (Claude Code, Cursor) can see it too.
17
+ **For Claude Desktop, the practical default is `claude_desktop`; use `meko_agent` for genuinely cross-client facts.** This controls attribution, not read visibility: the user's other agents can read either value.
18
+
19
+ **Don't write with another client's shape.** A Claude Desktop session that writes with `agent_id="claude_code"` (or `claude_code:something`) creates rows the UI will incorrectly attribute to Claude Code. Use `claude_desktop` when Desktop is running.
18
20
 
19
21
  ## Valid characters
20
22
 
21
23
  The server stores `agent_id` as a row-level column value — it never becomes a PostgreSQL identifier on Cloud. Any printable string works: colons, hyphens, dots, underscores, spaces. Stay within what's readable in the UI badge.
22
24
 
23
- Pre-existing data in real datapacks includes a mix of legacy shapes — `agent`, `claude-code`, `claude_code`, `cursor:<slug>`, `claude-code:-Users-...`, `claude-desktop` (hyphenated). None of them cause errors. To query those rows, pass the literal legacy value as `agent_id`. New writes should follow the table above.
25
+ Pre-existing data in real datapacks includes a mix of legacy shapes — `agent`, `claude-code`, `claude_code`, `cursor:<slug>`, `claude-code:-Users-...`, `claude-desktop` (hyphenated). None of them cause errors or prevent memory recall. New writes should follow the table above.
24
26
 
25
27
  ## How agent_id filters reads and writes
26
28
 
@@ -29,15 +31,19 @@ Pre-existing data in real datapacks includes a mix of legacy shapes — `agent`,
29
31
  - The row stores `(meko_datapack_id, meko_user_id, meko_agent_id)` — the user_id comes from your cognito account; the datapack_id defaults or is explicit; the agent_id is what you pass.
30
32
  - If you pass an empty or whitespace-only `agent_id`, the server stores `meko_agent`. That's the common bucket — fine for cross-client facts; not what you want for desktop-personal writes.
31
33
 
32
- ### Personal reads — `memory_search`, `memory_get_all`, `conversation_list`, `conversation_get`
34
+ ### Personal memory reads — `memory_search`, `memory_get_all`
35
+
36
+ Filter tuple: `(datapack_id, user_id)`. `agent_id` is not applied on memory reads.
33
37
 
34
- Filter tuple: `(datapack_id, user_id, agent_id)`.
38
+ - `user_id` is **always enforced**: one user cannot read another team member's un-promoted memories directly from MCP.
39
+ - `agent_id` does **not** filter results. One search returns this user's memories across every agent, including `claude_desktop`, project agents, legacy values, and the `meko_agent` common bucket.
35
40
 
36
- - `user_id` is **always enforced**: you can only see memories and conversations you wrote (or that other team members shared with you via promotion — see below). One user cannot read another team member's un-promoted memories directly from MCP.
37
- - `agent_id` is **strictly matched**: a search with `agent_id="claude_desktop"` returns only rows whose stored value is exactly that. Memories written from `agent_id="claude_code:foo"` are invisible to it.
38
- - An empty `agent_id` is rewritten to `meko_agent` server-side, so a "broad" read with empty string returns only common-bucket rows — **not** a cross-client fan-out. To search across multiple agent_ids, call once per known value.
41
+ Empirically verified 2026-07-23 on Cloud prod: memories written under two distinct `agent_id` values were both returned by a search using a third value.
39
42
 
40
- Empirically verified 2026-05-19 on Cloud prod (free-tier multitenant mode, segregation via row-level filter).
43
+ ### Personal conversation reads — `conversation_get`, `conversation_list`
44
+
45
+ - `conversation_get` is agent-owned: pass the exact `agent_id` that created the conversation.
46
+ - `conversation_list` is not agent-filtered and returns the datapack's conversations for this user across agents.
41
47
 
42
48
  ### Team-shared reads — `knowledgebase_search`
43
49
 
@@ -57,7 +63,8 @@ memory_add(agent_id=X, text=...)
57
63
  ▼
58
64
  mem0_collection ── personal memories, scoped (datapack, user, agent)
59
65
  │
60
- │ UI "Promote to Knowledge" (Learnings tab)
66
+ │ memory_promote (exact UUIDs + explicit confirmation)
67
+ │ or UI "Promote to Knowledge" (Learnings tab)
61
68
  │ ─────────────────────────────────────────
62
69
  │ Strips user_id, keeps agent_id as metadata,
63
70
  │ copies into team-shared table
@@ -70,23 +77,20 @@ knowledgebase_search(agent_id=anything, query=...)
70
77
 
71
78
  - **Personal memories** are what you get from `memory_search` / `memory_get_all`. Private to you.
72
79
  - **Shared Knowledge** is what you get from `knowledgebase_search`. Visible to every user and every agent on the datapack.
73
- - **Promotion is UI-only.** There is no MCP tool for promoting a memory to Shared Knowledge — the user triggers it from the datapack's Learnings tab in the Cloud UI.
80
+ - **Promotion has MCP and UI paths.** `memory_promote` moves exact, user-confirmed memories into Shared Knowledge and evicts the private records; the Learnings tab is the user-driven alternative. Only datapack owners and maintainers may use the MCP path.
74
81
 
75
82
  ## When to use what — broad-query guidance
76
83
 
77
- If the user asks "what do you know about X?" and you want to maximize recall:
78
-
79
- 1. **First call**: `memory_search(agent_id="claude_desktop", query="X")` — returns your desktop-personal memories.
80
- 2. **Second call**: `memory_search(agent_id="meko_agent", query="X")` — returns the common cross-project bucket: anything written with `agent_id="meko_agent"` from any client, plus rows the server stored under that name when called with empty `agent_id`.
81
- 3. **Third call**: `knowledgebase_search(agent_id="<anything>", datapack_id="<datapack>", query="X")` — returns team-shared knowledge. Useful when the answer may have been promoted by the user or a teammate.
84
+ If the user asks "what do you know about X?":
82
85
 
83
- For a true cross-agent fan-out (e.g. you also want to see what was written from `claude_code:some-repo` or `cursor:foo`), call `memory_search` once per known agent_id — the empty-string shortcut does not bypass the filter; the server rewrites empty to `meko_agent`.
86
+ 1. **`memory_search(agent_id="claude_desktop", query="X")`** — returns all of this user's personal memories across every agent. `agent_id` attributes the trace.
87
+ 2. **`knowledgebase_search(agent_id="<anything>", datapack_id="<datapack>", query="X")`** — returns team-shared knowledge. Useful when the answer may have been promoted by the user or a teammate.
84
88
 
85
- Always tell the user what scope you searched, so they understand why the answer is or isn't there. Example wording: "I found this in your desktop personal memories" vs. "I found this in your common cross-project bucket" vs. "I found this in your team's shared knowledge."
89
+ Always tell the user which surface you searched: personal memory or team-shared knowledge.
86
90
 
87
- ## Sub-scoping within an agent
91
+ ## Optional sub-scoping
88
92
 
89
- Optional parameters narrow further within the same `agent_id`:
93
+ Optional parameters can narrow a call further:
90
94
  - `user_id` — explicitly scope writes/reads to a specific end-user if your agent serves multiple (rare in Claude Desktop; more common in API products)
91
95
  - `run_id` — per-execution run
92
96
 
@@ -94,6 +98,6 @@ Available on `memory_add`, `memory_search`, `memory_get_all`, `memory_delete_all
94
98
 
95
99
  ## Things I checked and found in-data on real Cloud datapacks
96
100
 
97
- - `agent_id="agent"` appears on many legacy rows — it was the previous canonical constant. New writes should use the schema in the table above; query legacy rows with `agent_id="agent"` explicitly.
98
- - 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. The filtering is MCP-side only.
101
+ - `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.
102
+ - Memory Summary UI (`/datapacks/<name>/memory-summary`) shows every row for the user and renders the stored `agent_id` as a badge, consistent with cross-agent MCP memory reads.
99
103
  - 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 in the coding-agent skill.
@@ -0,0 +1,50 @@
1
+ # Authoring `reasoning` and `plan` on `conversation_add_message`
2
+
3
+ `conversation_add_message` accepts two optional fields — `reasoning` and `plan` — that capture *why* the assistant replied the way it did and *what* concrete steps it took. They are stored side-by-side on the per-turn `Reasoning` observation in Langfuse, independently, so consumers can read or render either one on its own.
4
+
5
+ Provide them on the large majority of substantive turns. Skip both only for genuinely trivial acknowledgements (a one-word reply, a pure restatement). Do not fabricate deliberation — but in practice, almost every substantive reply has at least a one-line *why* and a one-step plan.
6
+
7
+ ## `reasoning`
8
+
9
+ A short paragraph (1–3 sentences) of the **why**. Plain English. Explain which trade-off you weighed, which user fact tipped the decision, why this answer beat the alternatives. Inline markdown (`**bold**`, `*italics*`, `` `code` ``) is fine.
10
+
11
+ Do NOT include a `**Plan:**` heading inside `reasoning` — put steps in the `plan` field instead.
12
+
13
+ ## `plan`
14
+
15
+ A list of 2 to 4 concrete actions taken for this turn. Each entry is a single imperative sentence, like a checklist item. Pass a list of strings.
16
+
17
+ Do NOT pre-number entries. Do NOT include a `**Plan:**` heading inside the strings — `plan` is stored as a structured array on the observation's `metadata.plan`, independent of `reasoning`.
18
+
19
+ ## Two examples
20
+
21
+ ### Example A — database recommendation
22
+
23
+ ```
24
+ reasoning:
25
+ "The user cares about low latency and predictable cost.
26
+ Option A wins on latency but costs more per month; option
27
+ B is cheaper but adds 30 ms p99. Latency was their top
28
+ priority, so I picked Option A."
29
+
30
+ plan: [
31
+ "Recommend Option A and call out the latency advantage.",
32
+ "Show the monthly cost delta in clear numbers.",
33
+ "Flag the cost difference so the user can decide if it fits."
34
+ ]
35
+ ```
36
+
37
+ ### Example B — book pick for a long flight
38
+
39
+ ```
40
+ reasoning:
41
+ "The user wants a non-fiction book for a six-hour flight
42
+ and does not enjoy business memoirs. *Sapiens* fits the
43
+ time slot, is non-fiction, and is not a memoir."
44
+
45
+ plan: [
46
+ "Recommend *Sapiens* as the main pick.",
47
+ "Offer *Bad Blood* as a non-memoir backup.",
48
+ "Skip founder memoirs per the user's stated dislike."
49
+ ]
50
+ ```
@@ -1,21 +1,21 @@
1
1
  # Tool Cookbook — Complete Usage Examples
2
2
 
3
- Every tool example below shows the correct parameters, expected response, and common errors. Use `scope="read"` for reads and `scope="write"` for writes — never `"all"` or any other value.
3
+ Every tool example below shows the correct parameters, expected response, and common errors.
4
4
 
5
- > **Note on `agent_id` in the examples below.** The string `"agent"` appears in these examples as a placeholder shorthand; it is NOT a required constant. Substitute **your** client's bucket: for Claude Desktop, the bare client name `claude_desktop`; for Claude Code/Cursor, `<client>:<repo-basename>` (e.g. `claude_code:meko-mcp-server`). For genuinely cross-project facts (user identity, global preferences) write/read with `agent_id="meko_agent"` — the common bucket the server stores empty/missing values into. See `tools-agent-id-conventions.md`.
5
+ > **Note on `agent_id` in the examples below.** The string `"agent"` appears in these examples as a placeholder shorthand; it is NOT a required constant. Substitute **your** client's value: for Claude Desktop, use `claude_desktop`; for Claude Code/Cursor, use `<client>:<repo-basename>` (e.g. `claude_code:meko-mcp-server`). Write genuinely cross-project facts with `agent_id="meko_agent"`. On memory reads, `agent_id` attributes the trace but does not filter results. See `tools-agent-id-conventions.md`.
6
6
 
7
7
  ---
8
8
 
9
9
  ## Memory Tools
10
10
 
11
- **Critical:** Pass your session's `agent_id` on every memory call. For Claude Desktop that's `claude_desktop` for client-personal context, or `meko_agent` for genuinely cross-project facts (user identity, global preferences). Personal writes are scoped strictly by `agent_id` — other agents won't see your writes on personal reads unless they pass the same exact value.
11
+ **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.
12
12
 
13
13
  ### memory_add
14
14
 
15
15
  **When to use:** NOT for facts the user states — those are captured when you post the turn with `conversation_add_message` and the server extracts them. Reserve `memory_add` for the three cases per-turn capture can't reach: (1) the user explicitly says "remember this"; (2) a durable fact only in your output or a tool result, never in a user turn; (3) overwriting a negated/corrected fact (pair with `memory_delete_by_id`, since extraction is additive).
16
16
 
17
17
  ```
18
- memory_add(scope="write", agent_id="claude_desktop",
18
+ memory_add(agent_id="claude_desktop",
19
19
  text="Remember: deploy scripts must be run from the repo root, never a subdir.")
20
20
  ```
21
21
 
@@ -26,7 +26,7 @@ memory_add(scope="write", agent_id="claude_desktop",
26
26
 
27
27
  **With user scoping:**
28
28
  ```
29
- memory_add(scope="write", agent_id="agent", user_id="amiram",
29
+ memory_add(agent_id="agent", user_id="amiram",
30
30
  text="Prefers Python for backend, Go for infrastructure.")
31
31
  ```
32
32
 
@@ -44,8 +44,10 @@ memory_add(scope="write", agent_id="agent", user_id="amiram",
44
44
 
45
45
  **When to use:** Find relevant memories by meaning. Always try this before asking the user to repeat information.
46
46
 
47
+ **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
+
47
49
  ```
48
- memory_search(scope="read", query="What programming language does the team use?", agent_id="agent")
50
+ memory_search(query="What programming language does the team use?", agent_id="agent")
49
51
  ```
50
52
 
51
53
  **Response:**
@@ -55,7 +57,7 @@ memory_search(scope="read", query="What programming language does the team use?"
55
57
 
56
58
  **With limit:**
57
59
  ```
58
- memory_search(scope="read", query="user preferences", agent_id="agent", limit=5)
60
+ memory_search(query="user preferences", agent_id="agent", limit=5)
59
61
  ```
60
62
 
61
63
  ---
@@ -65,12 +67,12 @@ memory_search(scope="read", query="user preferences", agent_id="agent", limit=5)
65
67
  **When to use:** List everything stored for an agent. Useful at session start to load context.
66
68
 
67
69
  ```
68
- memory_get_all(scope="read", agent_id="agent")
70
+ memory_get_all(agent_id="agent")
69
71
  ```
70
72
 
71
73
  **With user scoping:**
72
74
  ```
73
- memory_get_all(scope="read", agent_id="agent", user_id="amiram")
75
+ memory_get_all(agent_id="agent", user_id="amiram")
74
76
  ```
75
77
 
76
78
  ---
@@ -78,7 +80,7 @@ memory_get_all(scope="read", agent_id="agent", user_id="amiram")
78
80
  ### memory_get_by_id
79
81
 
80
82
  ```
81
- memory_get_by_id(scope="read", memory_id="mem-uuid-123", agent_id="agent")
83
+ memory_get_by_id(memory_id="mem-uuid-123", agent_id="agent")
82
84
  ```
83
85
 
84
86
  ---
@@ -88,7 +90,7 @@ memory_get_by_id(scope="read", memory_id="mem-uuid-123", agent_id="agent")
88
90
  **When to use:** Overwrite a specific memory's text. Requires the memory UUID.
89
91
 
90
92
  ```
91
- memory_update(scope="write", memory_id="mem-uuid-123", text="Updated: Team uses Go for all new services", agent_id="agent")
93
+ memory_update(memory_id="mem-uuid-123", text="Updated: Team uses Go for all new services", agent_id="agent")
92
94
  ```
93
95
 
94
96
  ---
@@ -96,19 +98,39 @@ memory_update(scope="write", memory_id="mem-uuid-123", text="Updated: Team uses
96
98
  ### memory_delete_by_id
97
99
 
98
100
  ```
99
- memory_delete_by_id(scope="write", memory_id="mem-uuid-123", agent_id="agent")
101
+ memory_delete_by_id(memory_id="mem-uuid-123", agent_id="agent")
100
102
  ```
101
103
 
102
104
  ---
103
105
 
104
106
  ### memory_delete_all
105
107
 
106
- **Destructive. Requires admin scope.** Deletes all memories for the agent.
108
+ **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.
109
+
110
+ ```
111
+ memory_delete_all(agent_id="agent")
112
+ ```
113
+
114
+ ---
115
+
116
+ ### memory_promote
117
+
118
+ **When to use:** The user asks to share or promote specific memories to the team's knowledge base — the MCP counterpart of the Cloud UI's "Promote to Knowledge" flow. One-way: promoted memories become team-visible via `knowledgebase_search` and are evicted from the private memory store. Requires the caller to be a datapack **owner or maintainer**; viewers and contributors get a 403 permission error.
107
119
 
108
120
  ```
109
- memory_delete_all(scope="admin", agent_id="agent")
121
+ memory_promote(memory_ids=["mem-uuid-123", "mem-uuid-456"],
122
+ agent_id="claude_desktop", conversation_id="<uuid from conversation_create>")
110
123
  ```
111
124
 
125
+ **Response:**
126
+ ```json
127
+ {"inserted_ids": ["mem-uuid-123"], "updated_ids": ["mem-uuid-456"], "not_found_ids": []}
128
+ ```
129
+
130
+ Get exact UUIDs from the `id` field of `memory_search` / `memory_get_all` results; never use graph relation IDs. Before the call, show the user each exact memory and UUID, explain that promotion is team-visible, one-way, and evicts the private records, then obtain explicit confirmation for those candidates. Pass the active `conversation_id` and intended `agent_id` / `datapack_id`; on legacy schemas that expose `scope`, use `write`, not `admin`.
131
+
132
+ On 403, authentication, or permission failure, report the error and stop — do not escalate scope, change datapacks, or alter identity. After a successful call, `knowledgebase_search` may verify shared visibility, but it is not a rollback mechanism.
133
+
112
134
  ---
113
135
 
114
136
  ## Conversation Tools
@@ -118,7 +140,7 @@ memory_delete_all(scope="admin", agent_id="agent")
118
140
  **When to use:** Start storing a multi-turn exchange. Do this when the session contains valuable dialog worth preserving.
119
141
 
120
142
  ```
121
- conversation_create(scope="write", agent_id="agent", user_id="amiram",
143
+ conversation_create(agent_id="agent", user_id="amiram",
122
144
  title="Debugging the auth middleware")
123
145
  ```
124
146
 
@@ -133,23 +155,21 @@ conversation_create(scope="write", agent_id="agent", user_id="amiram",
133
155
 
134
156
  **When to use:** Add a user/assistant exchange to an existing conversation. **All fields must be verbatim** — never summarize or rephrase.
135
157
 
136
- Pass `index_for_search=True` on substantive turns so this conversation is embedded into the shared conversation-history cache (searchable later via `conversation_search` / `contextual_prominence_search`). This isn't limited to WorkbenchLM — pass it for agent-harness conversations too.
158
+ Leave `index_for_search` at its default (`False`). Conversation-cache embedding is currently a WorkbenchLM-only feature — the inference gateway opts in on its own turns; agent-harness conversations should not opt in.
137
159
 
138
160
  ```
139
- conversation_add_message(scope="write", conversation_id="conv-uuid-123", agent_id="agent",
161
+ conversation_add_message(conversation_id="conv-uuid-123", agent_id="agent",
140
162
  input="Why is the auth middleware returning 401?",
141
163
  output="The token validation is checking the wrong issuer claim...",
142
- reasoning="Checked the middleware source, found issuer mismatch between config and JWT...",
143
- index_for_search=True)
164
+ reasoning="Checked the middleware source, found issuer mismatch between config and JWT...")
144
165
  ```
145
166
 
146
167
  **With dedup seed (use when client hooks also write to Langfuse):**
147
168
  ```
148
- conversation_add_message(scope="write", conversation_id="conv-uuid-123", agent_id="agent",
169
+ conversation_add_message(conversation_id="conv-uuid-123", agent_id="agent",
149
170
  input="Why is the auth middleware returning 401?",
150
171
  output="The token validation is checking the wrong issuer claim...",
151
- seed="conv-uuid-123:agent:Why is the auth middleware returning 401?",
152
- index_for_search=True)
172
+ seed="conv-uuid-123:agent:Why is the auth middleware returning 401?")
153
173
  ```
154
174
 
155
175
  ---
@@ -157,7 +177,7 @@ conversation_add_message(scope="write", conversation_id="conv-uuid-123", agent_i
157
177
  ### conversation_get
158
178
 
159
179
  ```
160
- conversation_get(scope="read", conversation_id="conv-uuid-123", agent_id="agent",
180
+ conversation_get(conversation_id="conv-uuid-123", agent_id="agent",
161
181
  include_messages=True, limit=50)
162
182
  ```
163
183
 
@@ -165,8 +185,12 @@ conversation_get(scope="read", conversation_id="conv-uuid-123", agent_id="agent"
165
185
 
166
186
  ### conversation_list
167
187
 
188
+ Target the datapack by `datapack_id` (UUID). It's optional — omit it to use the
189
+ pinned/default datapack, or pass the pinned `datapack_id`. Use `datapack_list`
190
+ to look up the id.
191
+
168
192
  ```
169
- conversation_list(scope="read", agent_id="agent", limit=20)
193
+ conversation_list(datapack_id="<datapack-uuid>", agent_id="agent", limit=20)
170
194
  ```
171
195
 
172
196
  ---
@@ -174,7 +198,7 @@ conversation_list(scope="read", agent_id="agent", limit=20)
174
198
  ### conversation_update
175
199
 
176
200
  ```
177
- conversation_update(scope="write", conversation_id="conv-uuid-123", agent_id="agent",
201
+ conversation_update(conversation_id="conv-uuid-123", agent_id="agent",
178
202
  title="Resolved: Auth middleware issuer mismatch")
179
203
  ```
180
204
 
@@ -182,10 +206,10 @@ conversation_update(scope="write", conversation_id="conv-uuid-123", agent_id="ag
182
206
 
183
207
  ### conversation_delete
184
208
 
185
- **Destructive. Requires admin scope.**
209
+ **Destructive.**
186
210
 
187
211
  ```
188
- conversation_delete(scope="admin", conversation_id="conv-uuid-123", agent_id="agent")
212
+ conversation_delete(conversation_id="conv-uuid-123", agent_id="agent")
189
213
  ```
190
214
 
191
215
  ---
@@ -202,7 +226,6 @@ See `tools-rag-workflow.md` for the decision table.
202
226
 
203
227
  ```
204
228
  knowledgebase_search(
205
- scope="read",
206
229
  query="natural-language question",
207
230
  agent_id="agent",
208
231
  conversation_id="<uuid from conversation_create>",
@@ -229,7 +252,6 @@ Populated KBs return results with chunk content and similarity scores. An empty/
229
252
 
230
253
  ```
231
254
  artifact_put(
232
- scope="write",
233
255
  filename="analysis_report.csv",
234
256
  content_type="text/csv",
235
257
  content_base64="<base64-encoded bytes>",
@@ -265,7 +287,6 @@ Save the `content_hash` — it's the retrieval key for `artifact_get`.
265
287
  **Small files (< 1 MB) — content returned inline:**
266
288
  ```
267
289
  artifact_get(
268
- scope="read",
269
290
  content_hash="a665a45920422f9d417e4867efdc4fb8a5f1f89ea5b8440b1ad4c4c6b8a7e4d3",
270
291
  conversation_id="<uuid from conversation_create>",
271
292
  agent_id="claude_desktop"
@@ -305,16 +326,20 @@ For large files use `local_path` to read the file. S3 URLs are never exposed.
305
326
  ### datapack_create / datapack_list / datapack_describe
306
327
 
307
328
  ```
308
- datapack_create(scope="write", name="analytics_prod")
309
- datapack_list(scope="read") # returns datapack_id for each datapack
310
- datapack_describe(scope="read", datapack_id="<uuid>", include_status=True)
329
+ datapack_create(name="analytics_prod")
330
+ datapack_list() # returns datapack_id for each datapack
331
+ datapack_describe(datapack_id="<uuid>", include_status=True)
311
332
  ```
312
333
 
313
334
  ### datapack_update / datapack_delete
314
335
 
336
+ `datapack_update` renames or edits a datapack's description. At least one of `name` / `description` 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.
337
+
315
338
  ```
316
- datapack_update(scope="write", datapack_id="<uuid>", connection_string="postgresql://...")
317
- datapack_delete(scope="admin", datapack_id="<uuid>") # Irreversible!
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_delete(datapack_id="<uuid>") # Irreversible!
318
343
  ```
319
344
 
320
345
  ### Agent and knowledge-base management (NOT MCP — control-plane only)
@@ -322,6 +347,6 @@ datapack_delete(scope="admin", datapack_id="<uuid>") # Irreversible!
322
347
  Agent and KB lifecycle does not ship as MCP tools. If the user asks to create/list/delete agents or KB sources, don't invent a tool call — point them at the control plane:
323
348
 
324
349
  - REST: `POST/GET/DELETE /datapacks/:datapack_id/agents` (agents), `POST/GET/DELETE /datapacks/:datapack_id/knowledge-bases` (KB sources).
325
- - Or the Meko UI at `app.mekodev.com` → Datapacks → agents / knowledge-bases.
350
+ - Or the Meko Cloud UI at `cloud.mekodata.ai` → Datapacks → agents / knowledge-bases.
326
351
 
327
352
  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`.
@@ -36,7 +36,7 @@ It works **poorly** for:
36
36
 
37
37
  1. **Write a single narrative summary** as a memory — one call, not row-by-row:
38
38
  ```
39
- memory_add(scope="write",
39
+ memory_add(
40
40
  agent_id="<your session agent_id>",
41
41
  conversation_id="<session conversation_id>",
42
42
  text="Customer Complaints dataset has fields: Complaint ID (int PK), Date Submitted (date), Product (text, e.g. Mortgage/Credit Card), Sub-product (text), Issue (text), Company Response (text), State (text, 2-letter code), ZIP Code (text)")
@@ -56,8 +56,8 @@ 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 conversation search
59
+ ## No semantic search over conversation content
60
60
 
61
- `conversation_list` returns conversations by agent, but there is no semantic search across conversation content. To find a specific past exchange, you need to list conversations and inspect them individually with `conversation_get`.
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`.
62
62
 
63
- For finding past knowledge by meaning, use `memory_search` instead — which is why storing key facts via `memory_add` alongside conversations is important.
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.
@@ -11,10 +11,10 @@
11
11
  Memory is backed by pgvector (semantic search) and Apache AGE (entity-relationship graph). It retrieves relevant facts by meaning, not by conversation order.
12
12
 
13
13
  ```
14
- memory_add(scope="write", agent_id="support_bot",
14
+ memory_add(agent_id="support_bot",
15
15
  text="Customer Alice (alice@acme.com) prefers email, has Pro plan.", user_id="alice_123")
16
16
 
17
- memory_search(scope="read", query="What plan does Alice have?", agent_id="support_bot")
17
+ memory_search(query="What plan does Alice have?", agent_id="support_bot")
18
18
  ```
19
19
 
20
20
  ## Use `conversation_create` + `conversation_add_message` when storing:
@@ -26,10 +26,10 @@ memory_search(scope="read", query="What plan does Alice have?", agent_id="suppor
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(scope="write", agent_id="support_bot", user_id="alice_123", title="Pricing discussion")
29
+ conversation_create(agent_id="support_bot", user_id="alice_123", title="Pricing discussion")
30
30
  -- Returns: {"id": "conv-uuid-here"}
31
31
 
32
- conversation_add_message(scope="write", conversation_id="conv-uuid-here", agent_id="support_bot",
32
+ conversation_add_message(conversation_id="conv-uuid-here", agent_id="support_bot",
33
33
  input="What are your pricing tiers?",
34
34
  output="We offer Starter ($10/mo), Pro ($50/mo), and Enterprise (custom).",
35
35
  reasoning="Retrieved pricing page data. No special discounts apply.")
@@ -65,47 +65,44 @@ All three fields — `input`, `output`, and `reasoning` — must contain the **e
65
65
 
66
66
  The purpose of conversation storage is to create a faithful, replayable record. A rephrased summary loses the original wording, tone, and detail — making the stored conversation useless for review, debugging, or audit.
67
67
 
68
- ## Personal memory vs. team-shared knowledge — the three read paths
68
+ ## Personal memory vs. team-shared knowledge — the two read paths
69
69
 
70
- Agents on Cloud Meko have three distinct read surfaces. Pick the right one for the question.
70
+ Agents on Cloud Meko have two distinct read surfaces. Pick the right one for the question.
71
71
 
72
72
  | Read path | What it returns | How to call |
73
73
  |---|---|---|
74
- | Your own desktop memories | Memories you wrote under this `agent_id`, filtered by `(datapack_id, user_id, agent_id)` | `memory_search(agent_id="claude_desktop", query="...", ...)` |
75
- | Cross-project common bucket | Memories any agent (including this one) wrote with `agent_id="meko_agent"` — the empty-default bucket for genuinely cross-project facts | `memory_search(agent_id="meko_agent", query="...", ...)` |
74
+ | Your personal memories | Everything you and any of your agents wrote for this user, filtered by `(datapack_id, user_id)` and not by `agent_id` | `memory_search(agent_id="claude_desktop", query="...", ...)` — `agent_id` attributes the trace |
76
75
  | Team's shared knowledge | Promoted memories + uploaded documents, visible to every member of the datapack | `knowledgebase_search(agent_id="<anything>", datapack_id="<datapack UUID>", query="...")` — `agent_id` is ignored |
77
76
 
78
- For a true fan-out across other clients' buckets (e.g. also see what was written from `claude_code:some-repo` or `cursor:foo`), call `memory_search` once per agent_id — there's no single-call shortcut. Empty string is rewritten to `meko_agent` server-side; it does not drop the filter.
77
+ One `memory_search` already spans this user's memories across all agents; no per-agent fan-out is needed.
79
78
 
80
79
  ### How content gets into each surface
81
80
 
82
- - **Personal memories** — written by `memory_add`. Scoped per-user and per-agent from the moment of write. Only the writer sees them via MCP reads.
81
+ - **Personal memories** — written by `memory_add`. The `agent_id` records the writer but does not restrict reads; memories are scoped per-user, so any of that user's agents can read them and no other user can.
83
82
  - **Team-shared Shared Knowledge** — arrives two ways:
84
- 1. The **user** (never the agent) promotes a personal memory to Knowledge via the Cloud UI's Learnings tab. That copies the row into the shared `knowledge_base` table with the `user_id` stripped, making it team-wide. Originating `agent_id` is preserved in metadata for provenance.
83
+ 1. An agent calls `memory_promote` for exact, user-confirmed memory UUIDs, or the user promotes them from the Cloud UI's Learnings tab. Promotion moves the memories and graph context into shared knowledge, strips `user_id`, preserves originating `agent_id` as provenance, and evicts the private mem0 records.
85
84
  2. The user uploads a file via Datapack → Actions → **Add Knowledge** in the Cloud UI. PDF/TXT/MD/JSON/MP4 up to 5MB each.
86
85
 
87
86
  Both show up in `knowledgebase_search`, tagged `metadata_filters.source: "memory"` vs other values so the agent can distinguish provenance in responses.
88
87
 
89
- **No MCP tool promotes to Shared Knowledge.** The agent can flag memories it thinks are worth promoting and suggest the user do it from the UI — but the action is user-initiated.
88
+ `memory_promote` is a one-way, destructive MCP path. Before calling it, retrieve exact UUIDs with `memory_search` or `memory_get_all`, show the exact candidates, explain team visibility and private-record eviction, and obtain explicit user confirmation. Only owners and maintainers may promote; report 403/auth failures without escalating scope or switching datapacks. The Cloud UI remains an alternative.
90
89
 
91
90
  ### When the user asks "what do you know about X?"
92
91
 
93
- A full sweep is three calls (budget for it — each is 2-6 seconds):
92
+ A full sweep is two calls (budget for it — each is 2-6 seconds):
94
93
 
95
94
  ```
96
95
  memory_search(agent_id="claude_desktop", query="X", conversation_id=..., ...)
97
- memory_search(agent_id="meko_agent", query="X", conversation_id=..., ...) # cross-project common bucket
98
96
  knowledgebase_search(agent_id="<anything>", datapack_id="<uuid>", query="X", conversation_id=..., ...)
99
97
  ```
100
98
 
99
+ The single `memory_search` includes everything this user and their other agents wrote in the datapack.
100
+
101
101
  When you answer, be explicit about scope so the user knows why something is or isn't there:
102
102
 
103
- - "I found this in your own desktop memories…"
104
- - "I found this in your common cross-project bucket (something you or another agent wrote under `meko_agent`)…"
103
+ - "I found this in your personal memories (something you or another of your agents saved earlier)…"
105
104
  - "I found this in your team's Shared Knowledge — someone (you or a teammate) promoted it earlier…"
106
- - "I couldn't find anything in your personal memories. You might want to check the Cloud UI's Memory Summary tab for a cross-agent view."
107
-
108
- For a true fan-out across other clients' buckets (e.g. also see what was written from `claude_code:some-repo` or `cursor:foo`), call `memory_search` once per known agent_id — empty string just resolves to `meko_agent`, not a fan-out.
105
+ - "I couldn't find anything in your personal memories. You might want to check the Cloud UI's Memory Summary tab."
109
106
 
110
107
  ## Memory limitations for structured data
111
108