@yugabytedb/meko-mcp 1.0.3

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 (51) hide show
  1. package/README.md +505 -0
  2. package/assets/hooks-handlers/lib/capture.js +863 -0
  3. package/assets/hooks-handlers/lib/checkpoint-timer.js +72 -0
  4. package/assets/hooks-handlers/pre-compact.sh +3 -0
  5. package/assets/hooks-handlers/session-end.sh +27 -0
  6. package/assets/hooks-handlers/session-start.sh +24 -0
  7. package/assets/hooks-handlers/test_single_conversation.sh +169 -0
  8. package/assets/skills/meko-mcp-tools/SKILL.md +192 -0
  9. package/assets/skills/meko-mcp-tools/references/_sections.md +31 -0
  10. package/assets/skills/meko-mcp-tools/references/tools-agent-id-conventions.md +39 -0
  11. package/assets/skills/meko-mcp-tools/references/tools-conversation-dedup.md +49 -0
  12. package/assets/skills/meko-mcp-tools/references/tools-cookbook.md +373 -0
  13. package/assets/skills/meko-mcp-tools/references/tools-datapack-workflow.md +56 -0
  14. package/assets/skills/meko-mcp-tools/references/tools-db-query-patterns.md +38 -0
  15. package/assets/skills/meko-mcp-tools/references/tools-known-limitations.md +61 -0
  16. package/assets/skills/meko-mcp-tools/references/tools-memory-vs-conversation.md +128 -0
  17. package/assets/skills/meko-mcp-tools/references/tools-overview.md +97 -0
  18. package/assets/skills/meko-mcp-tools/references/tools-rag-workflow.md +63 -0
  19. package/assets/skills/meko-mcp-tools/references/tools-scope-permissions.md +79 -0
  20. package/assets/skills/meko-mcp-tools/references/tools-troubleshooting.md +143 -0
  21. package/assets/skills/meko-mcp-tools/references/tools-user-id-conventions.md +93 -0
  22. package/assets/skills/meko-mcp-tools/references/tools-write-guardrails.md +30 -0
  23. package/bin/create-meko-setup.mjs +499 -0
  24. package/lib/claude-code.mjs +14 -0
  25. package/lib/clients/claude-code.mjs +265 -0
  26. package/lib/clients/claude-desktop.mjs +256 -0
  27. package/lib/clients/common.mjs +107 -0
  28. package/lib/clients/cursor.mjs +332 -0
  29. package/lib/clients/index.mjs +14 -0
  30. package/lib/config.mjs +369 -0
  31. package/lib/detect.mjs +125 -0
  32. package/lib/installer.mjs +255 -0
  33. package/lib/logger.mjs +97 -0
  34. package/lib/mcp-transport.mjs +204 -0
  35. package/lib/migrate/adapters/claude-code.mjs +165 -0
  36. package/lib/migrate/adapters/cursor.mjs +221 -0
  37. package/lib/migrate/adapters/memory-md.mjs +230 -0
  38. package/lib/migrate/claude-parser.mjs +306 -0
  39. package/lib/migrate/daemon.mjs +67 -0
  40. package/lib/migrate/id.mjs +83 -0
  41. package/lib/migrate/lockfile.mjs +121 -0
  42. package/lib/migrate/logger.mjs +79 -0
  43. package/lib/migrate/mcp-client.mjs +224 -0
  44. package/lib/migrate/orchestrator.mjs +443 -0
  45. package/lib/migrate/progress.mjs +76 -0
  46. package/lib/migrate/state.mjs +177 -0
  47. package/lib/migrate.mjs +328 -0
  48. package/lib/prompt.mjs +212 -0
  49. package/lib/validate.mjs +259 -0
  50. package/package.json +49 -0
  51. package/scripts/bundle-assets.mjs +49 -0
@@ -0,0 +1,373 @@
1
+ # Tool Cookbook — Complete Usage Examples
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.
4
+
5
+ > **Note on `agent_id` in the examples below.** The examples use `agent_id="claude_code"` for readability, but `agent_id` is a **per-user namespace**, not a per-tool label. At runtime, use the value you discovered via `db_summarize_database` at session start (see the main SKILL.md). Substitute it anywhere you see `claude_code` in the examples. Issue [#10](https://github.com/amiramm/meko-mcp-server/issues/10) tracks the eventual schema fix.
6
+
7
+ ---
8
+
9
+ ## Database Tools
10
+
11
+ ### db_summarize_database
12
+
13
+ **When to use:** First thing in a session to understand what's in the database. Prefer this over writing your own `information_schema` query.
14
+
15
+ ```
16
+ db_summarize_database(scope="read", schema="public")
17
+ ```
18
+
19
+ **Response:**
20
+ ```json
21
+ [
22
+ {
23
+ "table_name": "customers",
24
+ "schema": [
25
+ {"column_name": "id", "data_type": "uuid"},
26
+ {"column_name": "name", "data_type": "text"}
27
+ ],
28
+ "row_count": 1523
29
+ }
30
+ ]
31
+ ```
32
+
33
+ **With datapack:**
34
+ ```
35
+ db_summarize_database(scope="read", schema="public", datapack_id="dp-uuid-123")
36
+ ```
37
+
38
+ **Common errors:**
39
+ - `Insufficient scope: 'all'` — Use `scope="read"`, not `"all"`
40
+ - Empty result — The schema may not exist, try `schema="public"`
41
+
42
+ ---
43
+
44
+ ### db_run_read_only_query
45
+
46
+ **When to use:** Any SELECT query. Always add `LIMIT` on exploratory queries.
47
+
48
+ ```
49
+ db_run_read_only_query(scope="read", query="SELECT id, name FROM customers LIMIT 10")
50
+ ```
51
+
52
+ **Response:** JSON array of row objects.
53
+ ```json
54
+ [{"id": "abc-123", "name": "Alice"}, {"id": "def-456", "name": "Bob"}]
55
+ ```
56
+
57
+ **Best practices:**
58
+ - Always use `LIMIT` on unfamiliar tables to avoid flooding context
59
+ - Select specific columns rather than `SELECT *` to keep responses small
60
+ - For non-public schemas: `SELECT * FROM analytics."monthly_revenue" LIMIT 5`
61
+ - Escape single quotes in values: `WHERE name = 'O''Brien'`
62
+
63
+ **Common errors:**
64
+ - `cannot execute INSERT in a read-only transaction` — Use `db_run_write_query` for writes
65
+ - `permission denied for table X` — MCP user lacks access to this table (server-side config issue, not fixable via MCP)
66
+ - `connection already closed` — Retry once. If persistent, the DB pool is unhealthy.
67
+
68
+ ---
69
+
70
+ ### db_run_write_query
71
+
72
+ **When to use:** INSERT, UPDATE, DELETE, CREATE TABLE, ALTER TABLE, DROP TABLE, CREATE INDEX.
73
+
74
+ ```
75
+ db_run_write_query(scope="write", query="INSERT INTO customers (id, name) VALUES ('abc-123', 'Alice')")
76
+ ```
77
+
78
+ **Response:**
79
+ ```json
80
+ {"rows_affected": 1}
81
+ ```
82
+
83
+ **One statement per call.** This is wrong:
84
+ ```
85
+ db_run_write_query(scope="write", query="CREATE TABLE a (id INT); CREATE TABLE b (id INT);")
86
+ ```
87
+ Split into two separate calls.
88
+
89
+ **Bulk inserts:** Maximum 1000 rows per INSERT VALUES. For more, use `INSERT ... SELECT` or batch into multiple calls.
90
+
91
+ **Common errors:**
92
+ - `Multi-statement queries not allowed` — Send one statement per call
93
+ - `DROP SCHEMA is not allowed` — See `tools-write-guardrails.md` for blocked operations
94
+ - `'dict' object has no attribute 'guardrail_config'` — Known server bug in some deployments. Write operations may be unavailable.
95
+
96
+ ---
97
+
98
+ ## Memory Tools
99
+
100
+ **Critical:** `agent_id` must not contain hyphens. Use `"claude_code"`, not `"claude-code"`.
101
+
102
+ ### memory_add
103
+
104
+ **When to use:** Store facts, preferences, user profile info, org conventions, corrections, learnings. Use proactively — don't wait for the user to ask.
105
+
106
+ ```
107
+ memory_add(scope="write", agent_id="claude_code",
108
+ text="User Amiram is VP of Product at YugabyteDB. Prefers concise responses.")
109
+ ```
110
+
111
+ **Response:**
112
+ ```json
113
+ {"results": [{"id": "mem-uuid-123", "memory": "User Amiram is VP of Product at YugabyteDB. Prefers concise responses."}]}
114
+ ```
115
+
116
+ **With user scoping:**
117
+ ```
118
+ memory_add(scope="write", agent_id="claude_code", user_id="amiram",
119
+ text="Prefers Python for backend, Go for infrastructure.")
120
+ ```
121
+
122
+ **What NOT to store via memory_add:**
123
+ - CSV rows or tabular data (use `db_run_write_query` instead)
124
+ - Full conversations (use `conversation_create` + `conversation_add_message`)
125
+ - Large documents (use knowledge base ingestion)
126
+
127
+ **Common errors:**
128
+ - `syntax error at or near "-"` — Your `agent_id` contains a hyphen. Use underscores.
129
+ - `connection already closed` — Retry once. If it fails again, the memory subsystem is down.
130
+
131
+ ---
132
+
133
+ ### memory_search
134
+
135
+ **When to use:** Find relevant memories by meaning. Always try this before asking the user to repeat information.
136
+
137
+ ```
138
+ memory_search(scope="read", query="What programming language does the team use?", agent_id="claude_code")
139
+ ```
140
+
141
+ **Response:**
142
+ ```json
143
+ {"results": [{"id": "mem-uuid-123", "memory": "Team uses Python for backend", "score": 0.89}]}
144
+ ```
145
+
146
+ **With limit:**
147
+ ```
148
+ memory_search(scope="read", query="user preferences", agent_id="claude_code", limit=5)
149
+ ```
150
+
151
+ ---
152
+
153
+ ### memory_get_all
154
+
155
+ **When to use:** List everything stored for an agent. Useful at session start to load context.
156
+
157
+ ```
158
+ memory_get_all(scope="read", agent_id="claude_code")
159
+ ```
160
+
161
+ **With user scoping:**
162
+ ```
163
+ memory_get_all(scope="read", agent_id="claude_code", user_id="amiram")
164
+ ```
165
+
166
+ ---
167
+
168
+ ### memory_get_by_id
169
+
170
+ ```
171
+ memory_get_by_id(scope="read", memory_id="mem-uuid-123", agent_id="claude_code")
172
+ ```
173
+
174
+ ---
175
+
176
+ ### memory_update
177
+
178
+ **When to use:** Overwrite a specific memory's text. Requires the memory UUID.
179
+
180
+ ```
181
+ memory_update(scope="write", memory_id="mem-uuid-123", text="Updated: Team uses Go for all new services", agent_id="claude_code")
182
+ ```
183
+
184
+ ---
185
+
186
+ ### memory_delete_by_id
187
+
188
+ ```
189
+ memory_delete_by_id(scope="write", memory_id="mem-uuid-123", agent_id="claude_code")
190
+ ```
191
+
192
+ ---
193
+
194
+ ### memory_delete_all
195
+
196
+ **Destructive. Requires admin scope.** Deletes all memories for the agent.
197
+
198
+ ```
199
+ memory_delete_all(scope="admin", agent_id="claude_code")
200
+ ```
201
+
202
+ ---
203
+
204
+ ## Conversation Tools
205
+
206
+ ### conversation_create
207
+
208
+ **When to use:** Start storing a multi-turn exchange. Do this when the session contains valuable dialog worth preserving.
209
+
210
+ ```
211
+ conversation_create(scope="write", agent_id="claude_code", user_id="amiram",
212
+ title="Debugging the auth middleware")
213
+ ```
214
+
215
+ **Response:**
216
+ ```json
217
+ {"id": "conv-uuid-123", "title": "Debugging the auth middleware"}
218
+ ```
219
+
220
+ ---
221
+
222
+ ### conversation_add_message
223
+
224
+ **When to use:** Add a user/assistant exchange to an existing conversation. **All fields must be verbatim** — never summarize or rephrase.
225
+
226
+ ```
227
+ conversation_add_message(scope="write", conversation_id="conv-uuid-123", agent_id="claude_code",
228
+ input="Why is the auth middleware returning 401?",
229
+ output="The token validation is checking the wrong issuer claim...",
230
+ reasoning="Checked the middleware source, found issuer mismatch between config and JWT...")
231
+ ```
232
+
233
+ **With dedup seed (use when client hooks also write to Langfuse):**
234
+ ```
235
+ conversation_add_message(scope="write", conversation_id="conv-uuid-123", agent_id="claude_code",
236
+ input="Why is the auth middleware returning 401?",
237
+ output="The token validation is checking the wrong issuer claim...",
238
+ seed="conv-uuid-123:claude_code:Why is the auth middleware returning 401?")
239
+ ```
240
+
241
+ ---
242
+
243
+ ### conversation_get
244
+
245
+ ```
246
+ conversation_get(scope="read", conversation_id="conv-uuid-123", agent_id="claude_code",
247
+ include_messages=True, limit=50)
248
+ ```
249
+
250
+ ---
251
+
252
+ ### conversation_list
253
+
254
+ ```
255
+ conversation_list(scope="read", agent_id="claude_code", limit=20)
256
+ ```
257
+
258
+ ---
259
+
260
+ ### conversation_update
261
+
262
+ ```
263
+ conversation_update(scope="write", conversation_id="conv-uuid-123", agent_id="claude_code",
264
+ title="Resolved: Auth middleware issuer mismatch")
265
+ ```
266
+
267
+ ---
268
+
269
+ ### conversation_delete_message
270
+
271
+ ```
272
+ conversation_delete_message(scope="write", conversation_id="conv-uuid-123",
273
+ agent_id="claude_code", trace_id="trace-uuid-456")
274
+ ```
275
+
276
+ ---
277
+
278
+ ### conversation_delete
279
+
280
+ **Destructive. Requires admin scope.**
281
+
282
+ ```
283
+ conversation_delete(scope="admin", conversation_id="conv-uuid-123", agent_id="claude_code")
284
+ ```
285
+
286
+ ---
287
+
288
+ ## RAG / Knowledge Base Tools
289
+
290
+ ### knowledgebase_trigger_index_creation
291
+
292
+ **When to use:** Create a new vector index from source URIs. This is the only way to start a RAG pipeline.
293
+
294
+ ```
295
+ knowledgebase_trigger_index_creation(scope="write",
296
+ source_uris="s3://my-bucket/docs/,s3://my-bucket/reports/",
297
+ index_name="company_docs")
298
+ ```
299
+
300
+ **Response:**
301
+ ```json
302
+ {"source_ids": ["src-uuid-1", "src-uuid-2"], "index_name": "company_docs", "status": "build_triggered"}
303
+ ```
304
+
305
+ **Optional parameters:**
306
+ - `ai_provider="OPENAI"` (default)
307
+ - `embedding_model="text-embedding-3-large"` (default)
308
+ - `embedding_dimensions=1536` (default)
309
+ - `chunk_size=1024` (default)
310
+ - `chunk_overlap=256` (default)
311
+ - `datapack_id=None`
312
+
313
+ **Warning:** Each call creates a new index. Do NOT retry on failure — you'll get duplicate indexes (e.g., `docs_v1`, `docs_v2`, `docs_v3`).
314
+
315
+ ---
316
+
317
+ ### knowledgebase_check_index_status
318
+
319
+ **When to use:** Poll for build completion after triggering creation.
320
+
321
+ ```
322
+ knowledgebase_check_index_status(scope="read", index_name="company_docs")
323
+ ```
324
+
325
+ **Polling strategy:** Check every 1-2 minutes. If `pipeline_details` is empty or documents remain at `INIT` for more than 5 minutes, the pipeline is likely stuck. Stop polling after 3 consecutive no-progress checks — see `tools-troubleshooting.md`.
326
+
327
+ ---
328
+
329
+ ### knowledgebase_add_source_to_index
330
+
331
+ **Known bug:** This tool has a parameter mismatch (`r_index_name` vs `r_index_id`) and may fail. Prefer `knowledgebase_trigger_index_creation` with all sources at once instead.
332
+
333
+ ```
334
+ knowledgebase_add_source_to_index(scope="write", index_name="company_docs",
335
+ source_id="src-uuid-new")
336
+ ```
337
+
338
+ ---
339
+
340
+ ## Datapack Management Tools
341
+
342
+ ### datapack_create / datapack_list / datapack_describe
343
+
344
+ ```
345
+ datapack_create(scope="write", name="analytics_prod")
346
+ datapack_list(scope="read")
347
+ datapack_describe(scope="read", name="analytics_prod", include_status=True)
348
+ ```
349
+
350
+ ### datapack_update / datapack_delete
351
+
352
+ ```
353
+ datapack_update(scope="write", name="analytics_prod", connection_string="postgresql://...")
354
+ datapack_delete(scope="admin", name="analytics_prod") # Irreversible!
355
+ ```
356
+
357
+ ### Agent management within datapacks
358
+
359
+ ```
360
+ datapack_create_agent(scope="write", datapack_name="analytics_prod", agent_name="analytics_bot")
361
+ datapack_list_agents(scope="read", datapack_name="analytics_prod")
362
+ datapack_delete_agent(scope="admin", datapack_name="analytics_prod", agent_name="analytics_bot")
363
+ ```
364
+
365
+ ### Knowledge base source management within datapacks
366
+
367
+ ```
368
+ datapack_add_knowledge_base(scope="write", datapack_name="analytics_prod", url="s3://data/reports/")
369
+ datapack_list_knowledge_bases(scope="read", datapack_name="analytics_prod")
370
+ datapack_delete_knowledge_base(scope="admin", datapack_name="analytics_prod", url="s3://data/reports/")
371
+ ```
372
+
373
+ **Note:** `datapack_delete_knowledge_base` removes the source registration from the Meko API. It does NOT delete the actual vector index, source records, or vector data from the database.
@@ -0,0 +1,56 @@
1
+ # Datapack Lifecycle and datapack_id Routing
2
+
3
+ **WRONG:** Creating a datapack then calling `db_summarize_database(scope="read")` without `datapack_id` — this queries the DEFAULT database, not the datapack.
4
+
5
+ ## Always pass datapack_id for datapack-scoped operations
6
+
7
+ ```
8
+ datapack_create(scope="write", name="analytics_prod")
9
+ -- Returns: {"id": "dp-uuid-123", ...}
10
+
11
+ db_summarize_database(scope="read", schema="public", datapack_id="dp-uuid-123")
12
+ db_run_read_only_query(scope="read", query="SELECT * FROM customers LIMIT 10", datapack_id="dp-uuid-123")
13
+ ```
14
+
15
+ ## How datapack_id routing works
16
+
17
+ 1. When `datapack_id` is **omitted**: uses the default pool from `YUGABYTEDB_URL`
18
+ 2. When `datapack_id` is **provided**: resolves connection string via Meko API, creates/reuses a cached pool for that datapack
19
+
20
+ ## Which tools accept datapack_id?
21
+
22
+ All **Database**, **RAG**, and **Memory** tools accept `datapack_id`.
23
+
24
+ **Conversation** tools do NOT — they always use Langfuse.
25
+ **Datapack management** tools do NOT — they operate on the Meko API itself.
26
+
27
+ ## How to obtain a datapack_id
28
+
29
+ - From `datapack_create` response (`"id"` field)
30
+ - From `datapack_list` (each entry has `"id"`)
31
+ - From `datapack_describe` response
32
+
33
+ ## Datapack lifecycle
34
+
35
+ ### Creation and setup
36
+
37
+ ```
38
+ datapack_create(scope="write", name="sales_analytics")
39
+ datapack_create_agent(scope="write", datapack_name="sales_analytics", agent_name="sales_agent")
40
+ datapack_add_knowledge_base(scope="write", datapack_name="sales_analytics", url="s3://company-docs/sales/")
41
+ db_run_write_query(scope="write", query="CREATE TABLE leads (...)", datapack_id="dp-uuid-from-step-1")
42
+ ```
43
+
44
+ ### Teardown (requires admin scope)
45
+
46
+ Delete child resources before the datapack:
47
+
48
+ ```
49
+ datapack_delete_knowledge_base(scope="admin", datapack_name="sales_analytics", url="s3://company-docs/sales/")
50
+ datapack_delete_agent(scope="admin", datapack_name="sales_analytics", agent_name="sales_agent")
51
+ datapack_delete(scope="admin", name="sales_analytics")
52
+ ```
53
+
54
+ ## Common mistake: mixing default and datapack databases
55
+
56
+ If you created a table with a `datapack_id`, always query it with the same `datapack_id`. Creating in default DB and querying in a datapack (or vice versa) will fail with "table not found".
@@ -0,0 +1,38 @@
1
+ # Read-Only vs Write Query Execution Patterns
2
+
3
+ **WRONG:** `db_run_write_query(scope="write", query="SELECT * FROM users")` — requires write scope unnecessarily, triggers guardrail validation, returns `{"rows_affected": -1}` instead of data.
4
+ **WRONG:** `db_run_read_only_query(scope="read", query="INSERT INTO ...")` — fails: "cannot execute INSERT in a read-only transaction."
5
+
6
+ ## How Each Tool Works
7
+
8
+ **`db_run_read_only_query`:** `BEGIN READ ONLY` → execute → `ROLLBACK`. Returns JSON array of row objects.
9
+
10
+ **`db_run_write_query`:** Guardrail validation → execute → `COMMIT`. Returns `{"rows_affected": N}`.
11
+
12
+ ## When to Use db_summarize_database
13
+
14
+ Use instead of writing your own `information_schema` query when you need a table overview:
15
+
16
+ ```
17
+ db_summarize_database(scope="read", schema="public")
18
+ -- Returns table names, column schemas, AND row counts in one call
19
+ ```
20
+
21
+ ## SQL Best Practices
22
+
23
+ **Schema qualification:** For non-public schemas, use `analytics."monthly_revenue"` and pass `schema="analytics"` to `db_summarize_database`.
24
+
25
+ **String escaping:** Queries are passed directly to `cur.execute()` — no parameter placeholders. Escape values in SQL: `WHERE name = 'O''Brien'`.
26
+
27
+ **LIMIT on exploratory queries:**
28
+ ```
29
+ db_run_read_only_query(scope="read", query="SELECT * FROM large_table LIMIT 25")
30
+ ```
31
+
32
+ **Batch large writes:** Due to the 1000-row INSERT cap, split large inserts. Or use `INSERT ... SELECT` for unlimited rows from an existing table.
33
+
34
+ **One statement per call:**
35
+ ```
36
+ WRONG: "CREATE TABLE a (id INT); CREATE TABLE b (id INT);"
37
+ RIGHT: Two separate db_run_write_query calls
38
+ ```
@@ -0,0 +1,61 @@
1
+ # Known Limitations
2
+
3
+ These are current limitations of the Meko MCP tools. Know them upfront to avoid wasted tool calls.
4
+
5
+ ## No delete tools for RAG artifacts
6
+
7
+ There are no MCP tools to:
8
+ - Delete a vector index
9
+ - Remove a source from an index
10
+ - Clear stuck work queue entries
11
+ - Reset a failed pipeline
12
+
13
+ The `datapack_delete_knowledge_base` tool only removes the KB source **registration** from the Meko API. It does NOT touch the actual `dist_rag` index, source records, or vector data in the database.
14
+
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
+
17
+ ## No MCP tool to query a built RAG index
18
+
19
+ The RAG tools (`knowledgebase_trigger_index_creation`, `knowledgebase_add_source_to_index`, `knowledgebase_check_index_status`) handle index **creation and monitoring** only.
20
+
21
+ To actually **query** a built index, use `db_run_read_only_query` with `dist_rag` SQL functions directly. The specific query syntax depends on the `dist_rag` extension API.
22
+
23
+ ## Memory tools unreliable for structured/tabular data
24
+
25
+ `memory_add` passes text through Mem0's fact extraction pipeline. This works well for:
26
+ - Facts: "Alice works at Acme Corp"
27
+ - Preferences: "User prefers dark mode"
28
+ - Entity relationships: "Amiram reports to Karthik"
29
+
30
+ It works **poorly** for:
31
+ - CSV rows or tabular data — columns and rows get dropped
32
+ - Data dictionaries — only partial information extracted
33
+ - Structured schemas — relationships between fields lost
34
+
35
+ **Use instead:** `db_run_write_query` to CREATE TABLE and INSERT the data as proper database rows. Then query it with `db_run_read_only_query`.
36
+
37
+ If you must store a schema overview in memory, write a single narrative summary:
38
+ ```
39
+ memory_add(scope="write", agent_id="claude_code",
40
+ 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)")
41
+ ```
42
+
43
+ ## MCP user permission gaps
44
+
45
+ The MCP database user may not have read access to all tables within a datapack, particularly:
46
+ - Data tables created by the provisioning system
47
+ - Tables in non-public schemas
48
+
49
+ If `db_run_read_only_query` returns "permission denied", this is a server-side configuration issue. Use `db_summarize_database` to see which tables are accessible.
50
+
51
+ ## Currently broken tools
52
+
53
+ **`db_run_write_query`** — May fail with `'dict' object has no attribute 'guardrail_config'` in some deployments. When this happens, all write operations are blocked for the session.
54
+
55
+ **`knowledgebase_add_source_to_index`** — SQL parameter mismatch: tool passes `r_index_name` (string) but the DB function expects `r_index_id` (UUID). Workaround: use `knowledgebase_trigger_index_creation` with all sources at once.
56
+
57
+ ## No conversation search
58
+
59
+ `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`.
60
+
61
+ For finding past knowledge by meaning, use `memory_search` instead — which is why storing key facts via `memory_add` alongside conversations is important.
@@ -0,0 +1,128 @@
1
+ # When to Use Memory Tools vs Conversation Tools
2
+
3
+ **WRONG:** `memory_add(text="User asked about pricing. I explained tiers. User chose Pro.")` — mem0 extracts facts, discarding conversational structure, turn ordering, and reasoning traces.
4
+
5
+ ## Use `memory_add` when storing:
6
+
7
+ - A **fact**: "User prefers dark mode"
8
+ - A **preference**: "Customer budget is $50k"
9
+ - An **entity relationship**: "Alice works at Acme Corp"
10
+
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
+
13
+ ```
14
+ memory_add(scope="write", agent_id="support_bot",
15
+ text="Customer Alice (alice@acme.com) prefers email, has Pro plan.", user_id="alice_123")
16
+
17
+ memory_search(scope="read", query="What plan does Alice have?", agent_id="support_bot")
18
+ ```
19
+
20
+ ## Use `conversation_create` + `conversation_add_message` when storing:
21
+
22
+ - A **full dialog exchange** with input/output pairs
23
+ - A **chain-of-thought** reasoning trace alongside the response
24
+ - A **multi-turn chat** where turn order matters
25
+
26
+ Conversations are backed by Langfuse sessions and traces. They preserve full structure: who said what, in what order, with what reasoning.
27
+
28
+ ```
29
+ conversation_create(scope="write", agent_id="support_bot", user_id="alice_123", title="Pricing discussion")
30
+ -- Returns: {"id": "conv-uuid-here"}
31
+
32
+ conversation_add_message(scope="write", conversation_id="conv-uuid-here", agent_id="support_bot",
33
+ input="What are your pricing tiers?",
34
+ output="We offer Starter ($10/mo), Pro ($50/mo), and Enterprise (custom).",
35
+ reasoning="Retrieved pricing page data. No special discounts apply.")
36
+ ```
37
+
38
+ ## Decision Matrix
39
+
40
+ | Signal | Tool |
41
+ |--------|------|
42
+ | "remember that...", "note that...", "keep in mind..." | `memory_add` |
43
+ | "store this conversation", "save this chat" | `conversation_create` + `conversation_add_message` |
44
+ | "what do you know about X?", "recall..." | `memory_search` |
45
+ | "show me our past conversation about..." | `conversation_list` + `conversation_get` |
46
+ | "the user prefers...", "their budget is..." | `memory_add` |
47
+ | "save my query and your response" | `conversation_add_message` |
48
+
49
+ ## Verbatim Content Rules for conversation_add_message
50
+
51
+ **WRONG:** Summarizing or rephrasing content before storing:
52
+ ```
53
+ conversation_add_message(...,
54
+ input="User inquired about database performance", -- rephrased
55
+ output="I provided optimization suggestions", -- summarized
56
+ reasoning="Analyzed the query and suggested improvements" -- condensed
57
+ )
58
+ ```
59
+
60
+ All three fields — `input`, `output`, and `reasoning` — must contain the **exact, verbatim text**. Never summarize, rephrase, editorialize, or condense any field:
61
+
62
+ - **`input`**: The user's exact prompt, word for word
63
+ - **`output`**: The assistant's complete response, word for word — including code blocks, formatting, and all detail
64
+ - **`reasoning`**: The full chain-of-thought or internal reasoning trace, unedited
65
+
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
+
68
+ ## Memory Limitations for Structured Data
69
+
70
+ **WRONG:** Using `memory_add` to ingest CSV rows, data dictionaries, or tabular schemas — Mem0 extracts individual facts and may drop columns, rows, or structural relationships.
71
+
72
+ For tabular data, prefer:
73
+ 1. **Create a table** via `db_run_write_query` and insert the data as rows — preserves all structure
74
+ 2. **Write a single narrative summary** as a memory: `"The Customer Complaints dataset has fields: Complaint ID (int), Date Submitted (date), Product (text), Sub-product (text), Issue (text)..."` — one call, not row-by-row
75
+ 3. **Never ingest CSV row-by-row** into memory — each row becomes a fragmented fact with lost context
76
+
77
+ ## Proactive Memory Storage
78
+
79
+ Don't wait for the user to say "remember this." Store context proactively when you detect:
80
+
81
+ - **Personal info** → `memory_add`: "User is VP of Product, prefers concise responses"
82
+ - **Team conventions** → `memory_add`: "Team uses Python for backend, Go for infrastructure"
83
+ - **Domain knowledge** → `memory_add`: "Meko traces are decision traces that capture how and why decisions were made"
84
+ - **Corrections** → `memory_add`: "User corrected: always use 'resilience' instead of 'high availability'"
85
+
86
+ Use `memory_search` at the start of sessions to recall what you already know before asking the user to repeat themselves.
87
+
88
+ ## Using Both Together
89
+
90
+ A common pattern: store the full conversation (preserves structure) AND extract key facts with `memory_add` (enables semantic search later).
91
+
92
+ ## Key Retrieval Difference
93
+
94
+ - `memory_search`: **semantic similarity** across all memories via pgvector. Returns relevant facts regardless of when stored.
95
+ - `conversation_get`: **ordered list of message turns** for a specific conversation. No semantic search. Requires `conversation_id`.
96
+
97
+ ## Automatic Conversation Capture
98
+
99
+ The Meko plugin captures conversations automatically via three mechanisms:
100
+
101
+ 1. **Periodic checkpoint (~10 min)** — Agent-driven via CronCreate, uses `conversation_add_message` MCP tool directly
102
+ 2. **PreCompact hook** — Shell script that fires before Claude Code's auto-compaction, captures via MCP JSON-RPC
103
+ 3. **SessionEnd hook** — Shell script that fires at session termination, captures final exchanges
104
+
105
+ ### What gets captured
106
+
107
+ The full transcript including:
108
+ - **User prompts** — verbatim text (the `input` field)
109
+ - **Assistant responses** — all text blocks (the `output` field)
110
+ - **Tool calls** — tool name + input parameters (the `reasoning` field)
111
+ - **Tool results** — output from tool executions (appended to `reasoning`)
112
+
113
+ This is more than just text — tool calls and results are critical context for session replay, cross-agent sharing, and compaction.
114
+
115
+ ### Seed-based deduplication
116
+
117
+ Each message's seed is `<conversation_id>:<user_message_uuid>`. All three capture mechanisms generate the same seed for the same exchange, producing the same deterministic trace ID via `sha256(seed)[:16].hex()`. This means duplicate writes from overlapping captures are idempotent.
118
+
119
+ ### When to manually store conversations
120
+
121
+ Automatic capture handles the raw exchange. You should still manually use `conversation_create` + `conversation_add_message` when:
122
+ - The user explicitly asks to "save this conversation"
123
+ - You want to add curated `reasoning` traces beyond raw tool calls
124
+ - You want to store a selected subset of the conversation with a descriptive title
125
+
126
+ ### Watermark coordination
127
+
128
+ A shared watermark file at `~/.claude/meko-capture/<session-id>.watermark.json` tracks what has been saved. Both hooks and the agent's periodic checkpoint use this to avoid reprocessing already-captured exchanges.