@yugabytedb/meko-mcp 1.1.0 → 2.0.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.
- package/README.md +81 -23
- package/assets/hooks-handlers/before-submit-prompt.sh +44 -0
- package/assets/hooks-handlers/cursor-session-start.sh +42 -0
- package/assets/hooks-handlers/lib/capture.js +404 -88
- package/assets/hooks-handlers/lib/checkpoint-timer.js +23 -11
- package/assets/hooks-handlers/session-start.sh +6 -2
- package/assets/scripts/meko-statusline.sh +119 -0
- package/assets/scripts/package-desktop-skill.sh +39 -0
- package/assets/skills/meko-mcp-tools/SKILL.md +42 -50
- package/assets/skills/meko-mcp-tools/references/_sections.md +1 -1
- package/assets/skills/meko-mcp-tools/references/tools-cookbook.md +75 -150
- package/assets/skills/meko-mcp-tools/references/tools-datapack-workflow.md +30 -36
- package/assets/skills/meko-mcp-tools/references/tools-known-limitations.md +6 -22
- package/assets/skills/meko-mcp-tools/references/tools-memory-vs-conversation.md +9 -8
- package/assets/skills/meko-mcp-tools/references/tools-overview.md +35 -42
- package/assets/skills/meko-mcp-tools/references/tools-rag-workflow.md +28 -92
- package/assets/skills/meko-mcp-tools/references/tools-scope-permissions.md +5 -9
- package/assets/skills/meko-mcp-tools/references/tools-troubleshooting.md +1 -81
- package/assets/skills/meko-mcp-tools-desktop/SKILL.md +244 -0
- package/assets/skills/meko-mcp-tools-desktop/desktop/README.md +180 -0
- package/assets/skills/meko-mcp-tools-desktop/references/_sections.md +24 -0
- package/assets/skills/meko-mcp-tools-desktop/references/tools-agent-id-conventions.md +99 -0
- package/assets/skills/meko-mcp-tools-desktop/references/tools-cookbook.md +327 -0
- package/assets/skills/meko-mcp-tools-desktop/references/tools-known-limitations.md +63 -0
- package/assets/skills/meko-mcp-tools-desktop/references/tools-memory-vs-conversation.md +214 -0
- package/assets/skills/meko-mcp-tools-desktop/references/tools-overview.md +105 -0
- package/assets/skills/meko-mcp-tools-desktop/references/tools-rag-workflow.md +70 -0
- package/assets/skills/meko-mcp-tools-desktop/references/tools-scope-permissions.md +71 -0
- package/assets/skills/meko-mcp-tools-desktop/references/tools-troubleshooting.md +75 -0
- package/assets/skills/meko-select-datapack-desktop/SKILL.md +198 -0
- package/assets/skills/meko-select-datapack-desktop/references/cookbook.md +121 -0
- package/assets/skills/meko-select-datapack-desktop/references/troubleshooting.md +66 -0
- package/bin/create-meko-setup.mjs +33 -4
- package/lib/clients/claude-code.mjs +133 -6
- package/lib/clients/claude-desktop.mjs +48 -20
- package/lib/clients/codex.mjs +538 -5
- package/lib/clients/common.mjs +122 -1
- package/lib/clients/cursor.mjs +120 -27
- package/lib/config.mjs +52 -0
- package/lib/installer.mjs +26 -2
- package/lib/mcp-transport.mjs +5 -0
- package/lib/validate.mjs +0 -1
- package/package.json +1 -1
- package/scripts/bundle-assets.mjs +16 -0
- package/assets/skills/meko-mcp-tools/references/tools-db-query-patterns.md +0 -38
- package/assets/skills/meko-mcp-tools/references/tools-write-guardrails.md +0 -30
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
# Complete Tool Catalog and Decision Tree
|
|
2
|
+
|
|
3
|
+
**22 tools on Cloud Meko** (verified against `https://mcp.mekodata.ai/mcp`). Grouped: Memory (8), Conversation (6), Knowledge Base (1), Datapack (5), Artifacts (2), Observability (1).
|
|
4
|
+
|
|
5
|
+
## Quick health check before using tools
|
|
6
|
+
|
|
7
|
+
Before starting a session, verify that the Meko MCP tools are working:
|
|
8
|
+
|
|
9
|
+
1. `memory_search(scope="read", 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`.
|
|
10
|
+
2. `datapack_list(scope="read")` — Confirms Meko API connectivity. Returns the datapacks your token has access to.
|
|
11
|
+
|
|
12
|
+
## Decision tree: which tool do I need?
|
|
13
|
+
|
|
14
|
+
```
|
|
15
|
+
User wants to...
|
|
16
|
+
├── Search a knowledge base? ---------------> knowledgebase_search (read)
|
|
17
|
+
├── Add documents to a knowledge base? -----> point user at Meko UI: Datapack → Actions → Add Knowledge
|
|
18
|
+
│ (no MCP tool — Cloud uses UI ingestion only)
|
|
19
|
+
├── Store or recall information?
|
|
20
|
+
│ ├── Store a fact/preference/entity? -----------> memory_add (write)
|
|
21
|
+
│ ├── Store a full conversation (multi-turn)? ---> conversation_create + conversation_add_message (write)
|
|
22
|
+
│ ├── Search past knowledge? --------------------> memory_search (read)
|
|
23
|
+
│ └── Retrieve a past conversation? -------------> conversation_get (read)
|
|
24
|
+
├── Persist or retrieve a file?
|
|
25
|
+
│ ├── Upload a generated file (report, CSV, PDF)? -> artifact_put (write)
|
|
26
|
+
│ └── Retrieve a previously uploaded file? -------> artifact_get (read)
|
|
27
|
+
└── Manage datapacks?
|
|
28
|
+
└── CRUD datapack? --------------------> datapack_create/list/describe/update/delete
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
Agent / knowledge-base lifecycle is managed **outside** the MCP surface — typically in the Meko control-plane UI — and is not exposed as tools here.
|
|
32
|
+
|
|
33
|
+
## Knowledge Base Tools (1)
|
|
34
|
+
|
|
35
|
+
| Tool | Scope | Purpose |
|
|
36
|
+
|------|-------|---------|
|
|
37
|
+
| `knowledgebase_search(scope, query, agent_id, conversation_id, datapack_id, limit=10)` | read | Semantic search across KB chunks. `datapack_id` is REQUIRED (no default). |
|
|
38
|
+
|
|
39
|
+
## Memory Tools (8)
|
|
40
|
+
|
|
41
|
+
| Tool | Scope | Purpose |
|
|
42
|
+
|------|-------|---------|
|
|
43
|
+
| `memory_add(scope, text, agent_id, conversation_id, user_id=None, app_id=None, run_id=None, metadata=None, messages=None, datapack_id=None)` | write | Store fact/preference/entity as long-term memory |
|
|
44
|
+
| `memory_search(scope, query, agent_id, conversation_id="", user_id=None, limit=10, datapack_id=None)` | read | Semantic search across memories + graph relations. `conversation_id` optional (omit or pass `""` for cross-conversation discovery). |
|
|
45
|
+
| `memory_get_by_id(scope, memory_id, agent_id, conversation_id, datapack_id=None)` | read | Direct pgvector row lookup by UUID. Preferred over `memory_search` for exact-id verification. |
|
|
46
|
+
| `memory_get_all(scope, agent_id, conversation_id, user_id=None, app_id=None, run_id=None, datapack_id=None)` | read | List all memories for agent |
|
|
47
|
+
| `memory_update(scope, memory_id, text, agent_id, conversation_id, datapack_id=None)` | write | Overwrite memory text |
|
|
48
|
+
| `memory_delete_by_id(scope, memory_id, agent_id, conversation_id, datapack_id=None)` | write | Delete a single memory |
|
|
49
|
+
| `memory_delete_all(scope, agent_id, conversation_id, user_id=None, app_id=None, run_id=None, datapack_id=None)` | admin | Delete all memories for agent (destructive) |
|
|
50
|
+
| `flush_pending_memory_candidates(scope, agent_id)` | read | **Deprecated.** Superseded by automatic extraction from posted turns — post substantive turns with `conversation_add_message` and the server extracts memories from them. Now returns a `deprecated` payload pointing at `conversation_add_message`; kept one release for backward compatibility. |
|
|
51
|
+
|
|
52
|
+
## Conversation Tools (6)
|
|
53
|
+
|
|
54
|
+
| Tool | Scope | Purpose |
|
|
55
|
+
|------|-------|---------|
|
|
56
|
+
| `conversation_create(scope, agent_id, user_id=None, app_id=None, run_id=None, title=None, metadata=None, session_id="")` | write | Create conversation container (Langfuse session) |
|
|
57
|
+
| `conversation_add_message(scope, conversation_id, agent_id, input, output=None, reasoning=None, metadata=None, seed=None, trace_id="")` | write | Add a message turn (Langfuse trace) |
|
|
58
|
+
| `conversation_get(scope, conversation_id, agent_id, include_messages=False, limit=100, offset=0)` | read | Retrieve conversation, optionally with messages |
|
|
59
|
+
| `conversation_list(scope, agent_id, conversation_id="", user_id=None, limit=20, offset=0)` | read | List conversations for agent. `conversation_id` optional (omit for browse). |
|
|
60
|
+
| `conversation_update(scope, conversation_id, agent_id, title=None, metadata=None)` | write | Update title or metadata |
|
|
61
|
+
| `conversation_delete(scope, conversation_id, agent_id)` | admin | Delete entire conversation (destructive) |
|
|
62
|
+
|
|
63
|
+
## Datapack Management Tools (5)
|
|
64
|
+
|
|
65
|
+
| Tool | Scope | Purpose |
|
|
66
|
+
|------|-------|---------|
|
|
67
|
+
| `datapack_create(scope, name)` | write | Create new datapack |
|
|
68
|
+
| `datapack_list(scope)` | read | List all datapacks |
|
|
69
|
+
| `datapack_describe(scope, datapack_id, include_status=False)` | read | Describe datapack by UUID |
|
|
70
|
+
| `datapack_update(scope, datapack_id, connection_string)` | write | Update connection string |
|
|
71
|
+
| `datapack_delete(scope, datapack_id)` | admin | Delete datapack by UUID (irreversible) |
|
|
72
|
+
|
|
73
|
+
## Artifact Tools (2)
|
|
74
|
+
|
|
75
|
+
Content-addressed blob store scoped to a datapack. Files < 1 MB go inline in the DB; files ≥ 1 MB go to S3. Identity is SHA-256 — uploading the same bytes twice returns the same `content_hash`. Free-tier artifacts expire after 30 days of inactivity; pro-tier artifacts have no TTL.
|
|
76
|
+
|
|
77
|
+
| Tool | Scope | Purpose |
|
|
78
|
+
|------|-------|---------|
|
|
79
|
+
| `artifact_put(scope, filename, content_base64, content_type, conversation_id, datapack_id=None, agent_id=None)` | write | Upload a file to the datapack. Returns `{artifact_id, content_hash, filename, size_bytes, stored_in}`. Max 5 MiB (configurable via `MEKO_MAX_ARTIFACT_UPLOAD_BYTES`). |
|
|
80
|
+
| `artifact_get(scope, content_hash, conversation_id, datapack_id=None, agent_id=None)` | read | Retrieve a file by SHA-256 hash. Small files return `content_base64` inline; large files (S3) are written to `~/.meko/artifacts/<hash>/<filename>` and `local_path` is returned. |
|
|
81
|
+
|
|
82
|
+
## Observability Tools (1)
|
|
83
|
+
|
|
84
|
+
| Tool | Scope | Purpose |
|
|
85
|
+
|------|-------|---------|
|
|
86
|
+
| `track_token_usage(scope, conversation_id, name, input_tokens=0, output_tokens=0, total_tokens=None, model=None, message_id=None, datapack_id=None)` | write | Record an LLM-cost GENERATION observation on the conversation's trace. Primarily called by first-party Meko services (e.g. inference_gateway) that know their LLM's exact token counts. Most end-agents (Cursor, Claude Desktop) don't have those counts at the MCP call layer, so this tool is rarely useful for third-party agents. |
|
|
87
|
+
|
|
88
|
+
## Platform capabilities NOT exposed via MCP
|
|
89
|
+
|
|
90
|
+
Some things the Meko platform can do are not wired into the MCP tool surface today. If a user asks about them, do not invent MCP tool calls — point them at the appropriate control plane instead. Agents attempting these as MCP tools will hit "tool not found".
|
|
91
|
+
|
|
92
|
+
| Capability | Where it lives | How to reach it |
|
|
93
|
+
|---|---|---|
|
|
94
|
+
| Create / list / delete **agents** within a datapack | `yugabyte/meko` API server | REST: `POST/GET/DELETE /datapacks/:datapack_id/agents` (`POST/GET/DELETE /agents/:agent` for targeted deletes), or the Meko control-plane UI |
|
|
95
|
+
| Add / list / delete **knowledge-base sources** on a datapack | `yugabyte/meko` API server | REST: `POST/GET/DELETE /datapacks/:datapack_id/knowledge-bases`, plus `upload-url`, `upload-complete`, `create`, `status` subroutes. Also available in the Meko UI. |
|
|
96
|
+
| Langfuse project-key generation | `yugabyte/meko` API server | REST: `POST /datapacks/:datapack_id/langfuse/project-keys` |
|
|
97
|
+
| Account / billing / tier management | Meko UI only | Not available via MCP or public REST |
|
|
98
|
+
|
|
99
|
+
The MCP-exposed `datapack_create` / `datapack_list` / `datapack_describe` / `datapack_update` / `datapack_delete` tools above are a deliberate subset — the common CRUD that an agent reasonably needs mid-conversation. Anything involving agent or KB lifecycle is control-plane territory.
|
|
100
|
+
|
|
101
|
+
For knowledge-base content on Cloud, the canonical path is **UI upload**: Datapack → Actions → **Add Knowledge** (PDF/TXT/MD/JSON/MP4, 5MB each, 10/batch). `knowledgebase_search` queries the resulting index from MCP.
|
|
102
|
+
|
|
103
|
+
## Common Parameter Patterns
|
|
104
|
+
|
|
105
|
+
Every tool accepts `scope` as the first parameter. 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`).
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# Knowledge Base / RAG workflow
|
|
2
|
+
|
|
3
|
+
`knowledgebase_search` is the only KB tool exposed via MCP. Index
|
|
4
|
+
creation and ingestion happen out of band — through the **Meko UI**
|
|
5
|
+
(`cloud.mekodata.ai`).
|
|
6
|
+
|
|
7
|
+
## Decision table
|
|
8
|
+
|
|
9
|
+
| Situation | Use this | Why |
|
|
10
|
+
|---|---|---|
|
|
11
|
+
| Search an existing KB | `knowledgebase_search` | The one KB tool exposed via MCP |
|
|
12
|
+
| 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
|
+
|
|
15
|
+
## knowledgebase_search — the one you'll actually call
|
|
16
|
+
|
|
17
|
+
```
|
|
18
|
+
knowledgebase_search(
|
|
19
|
+
scope="read",
|
|
20
|
+
query="natural-language question",
|
|
21
|
+
agent_id="claude_desktop",
|
|
22
|
+
conversation_id="<uuid from conversation_create>",
|
|
23
|
+
datapack_id="<datapack UUID — REQUIRED on this tool>",
|
|
24
|
+
limit=10)
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Required: `scope`, `query`, `agent_id`, `conversation_id`, `datapack_id`.
|
|
28
|
+
Unlike the memory tools, `datapack_id` has no default here — you must
|
|
29
|
+
pass it explicitly. `agent_id` is **ignored for filtering** on this
|
|
30
|
+
tool (KB results are team-shared on the datapack), but you still pass
|
|
31
|
+
it — your session's value is fine.
|
|
32
|
+
|
|
33
|
+
## Response shape
|
|
34
|
+
|
|
35
|
+
Populated KB:
|
|
36
|
+
|
|
37
|
+
```
|
|
38
|
+
{
|
|
39
|
+
"results": [
|
|
40
|
+
{
|
|
41
|
+
"content": "<chunk text>",
|
|
42
|
+
"similarity": 0.87,
|
|
43
|
+
"source_uri": "<original source URI>",
|
|
44
|
+
"document_name": "<file key>",
|
|
45
|
+
...
|
|
46
|
+
},
|
|
47
|
+
...
|
|
48
|
+
],
|
|
49
|
+
"count": <int>
|
|
50
|
+
}
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Empty or nonexistent KB: `{"results": [], "count": 0}` (no error,
|
|
54
|
+
just an empty array).
|
|
55
|
+
|
|
56
|
+
## UI ingestion — what the user sees
|
|
57
|
+
|
|
58
|
+
From `cloud.mekodata.ai`:
|
|
59
|
+
|
|
60
|
+
1. Open a datapack (`/datapacks/<name>`).
|
|
61
|
+
2. Click **Actions** → **Add Knowledge**.
|
|
62
|
+
3. Drag-and-drop or browse for files. Supported: PDF, TXT, MD, JSON,
|
|
63
|
+
MP4. Per-file limit 5 MB. Up to 10 files per batch.
|
|
64
|
+
4. The UI handles upload, storage, and index build. The user does not
|
|
65
|
+
pick a bucket or provide credentials.
|
|
66
|
+
5. Search results from `knowledgebase_search` become available once
|
|
67
|
+
indexing completes.
|
|
68
|
+
|
|
69
|
+
If a user asks you "how do I add a document to my knowledge base?",
|
|
70
|
+
point them at this flow.
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# Scope Permission Hierarchy and Per-Tool Requirements
|
|
2
|
+
|
|
3
|
+
**WRONG:** `memory_add(scope="read", ...)` → PermissionError: requires 'write' or higher.
|
|
4
|
+
**WRONG:** `memory_delete_all(scope="write", ...)` → PermissionError: requires 'admin'.
|
|
5
|
+
|
|
6
|
+
## Scope Hierarchy
|
|
7
|
+
|
|
8
|
+
```
|
|
9
|
+
admin (level 2) -- can do everything
|
|
10
|
+
↓
|
|
11
|
+
write (level 1) -- can read + write, not admin-only
|
|
12
|
+
↓
|
|
13
|
+
read (level 0) -- can only read
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
Higher scopes include lower scopes. An unrecognized scope string always fails.
|
|
17
|
+
|
|
18
|
+
## Per-Tool Requirements
|
|
19
|
+
|
|
20
|
+
### read scope (9 tools)
|
|
21
|
+
|
|
22
|
+
| Tool | Group |
|
|
23
|
+
|------|-------|
|
|
24
|
+
| `knowledgebase_search` | RAG |
|
|
25
|
+
| `memory_search` | Memory |
|
|
26
|
+
| `memory_get_by_id` | Memory |
|
|
27
|
+
| `memory_get_all` | Memory |
|
|
28
|
+
| `flush_pending_memory_candidates` | Memory |
|
|
29
|
+
| `conversation_get` | Conversation |
|
|
30
|
+
| `conversation_list` | Conversation |
|
|
31
|
+
| `datapack_list` | Datapack |
|
|
32
|
+
| `datapack_describe` | Datapack |
|
|
33
|
+
|
|
34
|
+
### write scope (9 tools)
|
|
35
|
+
|
|
36
|
+
| Tool | Group |
|
|
37
|
+
|------|-------|
|
|
38
|
+
| `memory_add` | Memory |
|
|
39
|
+
| `memory_update` | Memory |
|
|
40
|
+
| `memory_delete_by_id` | Memory |
|
|
41
|
+
| `conversation_create` | Conversation |
|
|
42
|
+
| `conversation_add_message` | Conversation |
|
|
43
|
+
| `conversation_update` | Conversation |
|
|
44
|
+
| `datapack_create` | Datapack |
|
|
45
|
+
| `datapack_update` | Datapack |
|
|
46
|
+
| `track_token_usage` | Observability |
|
|
47
|
+
|
|
48
|
+
### admin scope (3 tools — destructive, irreversible)
|
|
49
|
+
|
|
50
|
+
| Tool | Group |
|
|
51
|
+
|------|-------|
|
|
52
|
+
| `memory_delete_all` | Memory |
|
|
53
|
+
| `conversation_delete` | Conversation |
|
|
54
|
+
| `datapack_delete` | Datapack |
|
|
55
|
+
|
|
56
|
+
Agent and knowledge-base lifecycle tools are not MCP-exposed — see "Platform capabilities NOT exposed via MCP" in `tools-overview.md`.
|
|
57
|
+
|
|
58
|
+
## Best Practices
|
|
59
|
+
|
|
60
|
+
1. **Use the minimum scope needed.** `scope="read"` for reads documents intent and prevents accidental writes.
|
|
61
|
+
2. **The scope is a parameter, not an auth token.** When OAuth is enabled, the actual permission check happens against the OAuth token's claims. Both `scope` parameter and OAuth permissions must be satisfied.
|
|
62
|
+
|
|
63
|
+
## Common Mistakes
|
|
64
|
+
|
|
65
|
+
**WRONG:** `scope="all"` — there is no "all" scope. Valid values are exactly: `"read"`, `"write"`, `"admin"`. Nothing else.
|
|
66
|
+
|
|
67
|
+
Other invalid values that will fail: `"readwrite"`, `"rw"`, `"full"`, `"any"`.
|
|
68
|
+
|
|
69
|
+
The error `Insufficient scope: 'all'. This tool requires 'read' or higher.` means the scope string was not recognized as a valid value. Always use one of the three valid strings.
|
|
70
|
+
|
|
71
|
+
**Default choice:** Start with `scope="read"` unless you specifically need to write or delete.
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
# Troubleshooting — Error Recovery and Retry Strategies
|
|
2
|
+
|
|
3
|
+
These patterns are extracted from real agent sessions. Follow them to avoid wasting tool calls and context window on repeated failures.
|
|
4
|
+
|
|
5
|
+
## General rules
|
|
6
|
+
|
|
7
|
+
1. **Never retry the identical failed call more than once.** If it fails twice with the same error, it's not transient — diagnose the cause.
|
|
8
|
+
2. **Distinguish transient vs persistent failures.** "Connection already closed" is transient (retry once). "Permission denied" is persistent (stop, don't retry).
|
|
9
|
+
3. **Don't guess parameters sequentially.** If a tool fails with one parameter format, don't try 4 variations. Check this skill's docs for the correct format first.
|
|
10
|
+
4. **Use your session's `agent_id` consistently.** For Claude Desktop the default is `claude_desktop`; for cross-project common facts use `meko_agent`. Other clients use `<client>:<repo-basename>` (e.g. `claude_code:meko-mcp-server`). Use `agent_id="meko_agent"` deliberately on `memory_search`/`memory_get_all` only when you want the common bucket — empty string also resolves to `meko_agent`, not a cross-agent fan-out. Don't switch between forms mid-session.
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## Connection errors: "connection already closed"
|
|
15
|
+
|
|
16
|
+
**Affects:** Memory tools (`memory_add`, `memory_search`, `memory_get_all`) most frequently.
|
|
17
|
+
|
|
18
|
+
**Why it happens:** The Python memory subsystem uses a connection cache that doesn't recover from dropped connections (unlike the Go API server which has retry logic with 5 retries and 3-second delays).
|
|
19
|
+
|
|
20
|
+
**What to do:**
|
|
21
|
+
|
|
22
|
+
1. Retry the same call **once**.
|
|
23
|
+
2. If it fails again, the memory subsystem is unhealthy for this session — stop trying memory calls and tell the user. Do not waste tokens re-sending the same payload.
|
|
24
|
+
|
|
25
|
+
**Anti-pattern from real sessions:** Agent called `memory_add` with 500+ tokens of text, got "connection already closed", retried the identical call 3 more times (each 500+ tokens). Wasted ~2000 tokens on guaranteed failures.
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
## Scope parameter errors
|
|
30
|
+
|
|
31
|
+
**Error:** `Insufficient scope: 'all'. This tool requires 'read' or higher.`
|
|
32
|
+
|
|
33
|
+
The only valid scope values are: `"read"`, `"write"`, `"admin"`.
|
|
34
|
+
|
|
35
|
+
- Use `"read"` for all read operations (default choice)
|
|
36
|
+
- Use `"write"` for inserts, updates, creates, memory writes
|
|
37
|
+
- Use `"admin"` only for destructive deletes
|
|
38
|
+
|
|
39
|
+
**Never use:** `"all"`, `"readwrite"`, `"rw"`, or any other value.
|
|
40
|
+
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
## agent_id errors
|
|
44
|
+
|
|
45
|
+
On the Cloud multi-tenant schema, `agent_id` is a TEXT column value — not a PostgreSQL identifier — so arbitrary strings are accepted.
|
|
46
|
+
|
|
47
|
+
`agent_id` is **not a constant**. Cloud Meko supports multiple agents on one datapack, and the Cloud UI renders every `agent_id` as a badge on each row regardless of value. The canonical shape for new writes is `<client>:<repo-basename>` for coding agents (e.g. `claude_code:meko-mcp-server`), a bare client name for non-coding clients like Claude Desktop (`claude_desktop`), or `meko_agent` for the cross-project common bucket — see `tools-agent-id-conventions.md`.
|
|
48
|
+
|
|
49
|
+
### "My writes are landing in `meko_agent` instead of my agent's bucket"
|
|
50
|
+
|
|
51
|
+
If you call `memory_add` with empty / None / whitespace `agent_id`, the server does NOT reject the write. It silently resolves the value to `meko_agent` (the cross-project common bucket) and the row lands there. The Cloud UI then shows a `meko_agent` badge instead of your client's badge.
|
|
52
|
+
|
|
53
|
+
Fix: always pass a concrete non-empty `agent_id`. For Claude Desktop use `agent_id="claude_desktop"`; for hook-driven clients (Claude Code, Cursor) fetch the value the SessionStart hook injected into `additionalContext` and pass it verbatim. Use `agent_id="meko_agent"` only when you genuinely want a fact in the cross-project pool (user identity, global preferences).
|
|
54
|
+
|
|
55
|
+
### "My reads return fewer results than I expected"
|
|
56
|
+
|
|
57
|
+
`memory_search` and `memory_get_all` filter strictly on your passed `agent_id`. A memory written by `claude-code:<slug-A>` is invisible to a search with `agent_id="cursor:<slug-B>"`. If you need a broader view, call repeatedly across the agent_ids you want to cover, or point the user at the UI's Memory Summary page (which shows every row regardless of agent_id).
|
|
58
|
+
|
|
59
|
+
### "I'm seeing rows tagged with legacy agent_id values"
|
|
60
|
+
|
|
61
|
+
Pre-existing data may be tagged `"agent"`, `"claude_code"`, `"cursor:<slug>"`, or similar ad-hoc values. All remain readable. New writes should follow the canonical `<client>:<project-slug>` form; don't try to retag old rows.
|
|
62
|
+
|
|
63
|
+
---
|
|
64
|
+
|
|
65
|
+
## Safe-to-retry vs not
|
|
66
|
+
|
|
67
|
+
| Tool | Safe to retry? | Why |
|
|
68
|
+
|------|---------------|-----|
|
|
69
|
+
| All `read` scope tools | Yes | Reads are idempotent |
|
|
70
|
+
| `memory_add` | Yes (once) | Mem0 has dedup logic |
|
|
71
|
+
| `memory_update` | Yes (once) | Overwrites same ID |
|
|
72
|
+
| `memory_delete_by_id` | Yes | Deleting already-deleted is a no-op |
|
|
73
|
+
| `conversation_create` | **No** | Creates duplicate conversations |
|
|
74
|
+
| `conversation_add_message` with `seed` | Yes | Seed-based dedup prevents duplicates |
|
|
75
|
+
| `conversation_add_message` without `seed` | **No** | Creates duplicate messages |
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: meko-select-datapack-desktop
|
|
3
|
+
description: >-
|
|
4
|
+
Lists the user's Meko datapacks, shows authorization, supports search and
|
|
5
|
+
pagination, and pins one as the active datapack on Claude Desktop. Triggers
|
|
6
|
+
when the user says things like "switch datapack", "use datapack <name>",
|
|
7
|
+
"list my datapacks", "which datapack am I on", "pin <name>", or any request
|
|
8
|
+
to change or inspect the active datapack. Persistence is via memory_add
|
|
9
|
+
(Desktop has no SessionStart hook), so the pin survives across sessions
|
|
10
|
+
until the user clears it.
|
|
11
|
+
license: MIT
|
|
12
|
+
metadata:
|
|
13
|
+
author: Meko
|
|
14
|
+
version: "1.1.0"
|
|
15
|
+
tags: meko, datapack, selection, project, claude-desktop, desktop
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
# meko-select-datapack-desktop — Pin a datapack for Claude Desktop
|
|
19
|
+
|
|
20
|
+
Claude Desktop has no SessionStart hook, so the Claude Code variant's sidecar/hook design doesn't apply here. Instead, the pin is stored as a **memory** with a structured tag, scoped to `agent_id="claude_desktop"` (Desktop's project bucket), and you re-read it on every Desktop turn before issuing Meko MCP tool calls. The pin outlives a single Desktop conversation — it sticks until the user explicitly clears it. Same project-scoped semantic as the Claude Code variant; different mechanism.
|
|
21
|
+
|
|
22
|
+
## How persistence works (Desktop)
|
|
23
|
+
|
|
24
|
+
A single memory under `agent_id="claude_desktop"` carries the pin:
|
|
25
|
+
|
|
26
|
+
```
|
|
27
|
+
text: "meko_active_datapack=<uuid> name=<name> selected_at=<iso8601>"
|
|
28
|
+
metadata: { "type": "active-datapack-pin" }
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
You discover it by calling `memory_search(query="meko_active_datapack", agent_id="claude_desktop", limit=1)` at the start of any turn that's about to make a Meko MCP write. If you find a pin, pass `datapack_id="<uuid>"` to every Meko call that accepts it. If you don't find one, fall back to the server default (omit the parameter).
|
|
32
|
+
|
|
33
|
+
## When to invoke this skill
|
|
34
|
+
|
|
35
|
+
Trigger immediately on any of these signals:
|
|
36
|
+
|
|
37
|
+
- User says "switch datapack", "change datapack", "use datapack X", "select datapack", "pick a datapack".
|
|
38
|
+
- User says "list my datapacks", "what datapacks do I have", "show me my datapacks".
|
|
39
|
+
- User says "which datapack am I on", "which datapack is active", "what's pinned".
|
|
40
|
+
- User says "clear datapack", "unpin datapack", "stop using <name>".
|
|
41
|
+
- The first Meko MCP write of a turn AND `memory_search` for `meko_active_datapack` returned no result AND the user has more than one datapack — proactively offer to pin one.
|
|
42
|
+
|
|
43
|
+
## On every Meko-touching turn (not just when this skill triggers)
|
|
44
|
+
|
|
45
|
+
Before issuing a Meko MCP write tool call (memory_add, db_run_write_query, conversation_add_message, etc.), if you don't already know the active pin from this turn's earlier work:
|
|
46
|
+
|
|
47
|
+
```
|
|
48
|
+
memory_search(scope="read",
|
|
49
|
+
query="meko_active_datapack",
|
|
50
|
+
agent_id="claude_desktop",
|
|
51
|
+
conversation_id="<this conversation's id>",
|
|
52
|
+
limit=1)
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Parse the result. If a pin row is present, extract the UUID from the text body (after `meko_active_datapack=`) and pass it as `datapack_id` to every Meko MCP call this turn. If not, omit `datapack_id` and let the server resolve the default.
|
|
56
|
+
|
|
57
|
+
This is once per turn, not once per call. Cache within the turn.
|
|
58
|
+
|
|
59
|
+
## The flow
|
|
60
|
+
|
|
61
|
+
### 1. List
|
|
62
|
+
|
|
63
|
+
Use a **temporary** conversation for browsing only. Call
|
|
64
|
+
`conversation_create(scope="write", agent_id="claude_desktop", title="Claude
|
|
65
|
+
Desktop datapack selection")` and use its returned ID for the read-only
|
|
66
|
+
`datapack_list` below and for the pin `memory_add`/`memory_update` in step 4.
|
|
67
|
+
|
|
68
|
+
**Do not reuse this conversation for later capture.** It lives in whatever
|
|
69
|
+
datapack was active when it was created (typically the default), and a
|
|
70
|
+
conversation cannot move between datapacks. Once a datapack is pinned, capture
|
|
71
|
+
must flow through a *new* conversation created in the selected datapack — see
|
|
72
|
+
step 5.
|
|
73
|
+
|
|
74
|
+
```
|
|
75
|
+
datapack_list(scope="read", conversation_id="<this conversation's id>")
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
The response is an array; the fields you'll use are `datapack_id`,
|
|
79
|
+
`datapack_name`, `created_at`, and `account_id`.
|
|
80
|
+
|
|
81
|
+
If the response has zero entries, tell the user: *"You don't have any datapacks yet. Run `datapack_create(scope='admin', name='<name>')` to make one, or visit the Meko Cloud console."* Stop here.
|
|
82
|
+
|
|
83
|
+
If the response has exactly **one** entry, **auto-select it**. Print: *"Only one datapack: `<name>`. Auto-selecting. Run `meko-select-datapack-desktop` again with `clear` to unset."* Skip the table; jump to step 4 (persist) and step 5 (confirm).
|
|
84
|
+
|
|
85
|
+
### 2. Render the table
|
|
86
|
+
|
|
87
|
+
For 2+ datapacks, render a numbered table. **Page size 10.** Default sort: `created_at DESC` (newest first).
|
|
88
|
+
|
|
89
|
+
```
|
|
90
|
+
Your datapacks (showing 1-10 of 14):
|
|
91
|
+
|
|
92
|
+
# Name Role Created Status Active?
|
|
93
|
+
1 meko-local-setup Owner 2026-04-30 ready ← (pinned)
|
|
94
|
+
2 meko_default_datapack Owner 2026-04-30 ready
|
|
95
|
+
3 prod-research Owner 2026-04-12 ready
|
|
96
|
+
…
|
|
97
|
+
|
|
98
|
+
Reply with: a number (1-10) to pin · a substring to search · `next` / `prev` to page
|
|
99
|
+
· `clear` to unset · `cancel` to leave the current pin alone
|
|
100
|
+
|
|
101
|
+
Note: Role is hardcoded to "Owner" today. Shared / Viewer / Contributor /
|
|
102
|
+
Maintainer roles are pending upstream backend work — see references/role-display-future.md.
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
Mark the currently-pinned row with `← (pinned)` based on the `memory_search` result (if any).
|
|
106
|
+
|
|
107
|
+
### 3. Parse the user's reply
|
|
108
|
+
|
|
109
|
+
- **Integer in range** → that row is the choice.
|
|
110
|
+
- **Substring** → re-render filtered. If it narrows to one row, that's the choice.
|
|
111
|
+
- **`next` / `prev`** → re-render next/previous page.
|
|
112
|
+
- **`cancel`** → leave any existing pin in place; print *"Cancelled. Active datapack unchanged."* Stop.
|
|
113
|
+
- **`clear` / `none` / `unpin`** → see step 4's clear path.
|
|
114
|
+
- **Unrecognized** → re-prompt with the legend.
|
|
115
|
+
|
|
116
|
+
### 4. Persist
|
|
117
|
+
|
|
118
|
+
**On first pin (no existing pin memory):**
|
|
119
|
+
|
|
120
|
+
```
|
|
121
|
+
memory_add(scope="write",
|
|
122
|
+
text="meko_active_datapack=<uuid> name=<name> selected_at=<iso8601>",
|
|
123
|
+
agent_id="claude_desktop",
|
|
124
|
+
conversation_id="<this conversation's id>",
|
|
125
|
+
metadata='{"type":"active-datapack-pin"}')
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
Verify the write with `memory_search` (the standard Meko verify-after-write rule from `meko-mcp-tools-desktop`). Capture the returned memory `id`.
|
|
129
|
+
|
|
130
|
+
**On switch (existing pin memory found):**
|
|
131
|
+
|
|
132
|
+
```
|
|
133
|
+
memory_update(scope="write",
|
|
134
|
+
memory_id="<existing pin id>",
|
|
135
|
+
text="meko_active_datapack=<new uuid> name=<new name> selected_at=<iso8601>",
|
|
136
|
+
agent_id="claude_desktop",
|
|
137
|
+
conversation_id="<this conversation's id>")
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
Always update — never `memory_add` a second pin. Two pin memories will produce ambiguous reads.
|
|
141
|
+
|
|
142
|
+
**On clear:**
|
|
143
|
+
|
|
144
|
+
```
|
|
145
|
+
memory_delete_by_id(scope="write",
|
|
146
|
+
memory_id="<existing pin id>",
|
|
147
|
+
agent_id="claude_desktop",
|
|
148
|
+
conversation_id="<this conversation's id>")
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
If `memory_search` returned no pin, there's nothing to delete — print *"No pin was set; nothing to clear."* and stop.
|
|
152
|
+
|
|
153
|
+
**Conversation transition after a clear (same rule as a switch).** The pin memory is now gone, but the session's current conversation still physically lives in the datapack that was pinned when it was created — a conversation cannot move to the default. You must pick exactly one of these; do not mix them:
|
|
154
|
+
|
|
155
|
+
- **Option A — keep capturing to the current conversation this session.** It stays in its original (now-unpinned) datapack, so you must keep passing that **same old `datapack_id`** on its `conversation_add_message` calls — do NOT switch it to the default (that would fail). The clear only affects *new* sessions. Disclose: *"Pin cleared. This chat keeps saving to `<old datapack name>`; new chats will use the default datapack."*
|
|
156
|
+
- **Option B — start default-datapack capture immediately.** Create a **new** conversation with no `datapack_id` (`conversation_create(scope="write", agent_id="claude_desktop")`) and post all subsequent turns there. Stop posting to the old conversation. Disclose: *"Pin cleared. Started a new chat context saving to the default datapack."*
|
|
157
|
+
|
|
158
|
+
Default to Option A (least disruptive) unless the user wants the switch to take effect right now. Either way, never send `datapack_id=default` to the pre-existing pinned conversation.
|
|
159
|
+
|
|
160
|
+
### 5. Confirm
|
|
161
|
+
|
|
162
|
+
```
|
|
163
|
+
Pinned datapack `<name>` (`<uuid>`) for Claude Desktop.
|
|
164
|
+
|
|
165
|
+
This is stored as a memory under agent_id="claude_desktop". It will persist
|
|
166
|
+
across sessions until you run this skill again with `clear` (or `switch` to
|
|
167
|
+
a different datapack).
|
|
168
|
+
|
|
169
|
+
I'll read this pin via `memory_search` before each Meko MCP write so the
|
|
170
|
+
right `datapack_id` flows through automatically.
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
**Then start a fresh conversation for capture in the selected datapack.** The
|
|
174
|
+
temporary selection conversation from step 1 belongs to the datapack that was
|
|
175
|
+
active when it was created and cannot be moved. For subsequent capture this
|
|
176
|
+
session, call `conversation_create(scope="write", agent_id="claude_desktop",
|
|
177
|
+
datapack_id="<the newly pinned uuid>", title="<topic>")` and post turns
|
|
178
|
+
(`conversation_add_message`) to *that* conversation with the same
|
|
179
|
+
`datapack_id`. Do not keep posting to the selection conversation — doing so
|
|
180
|
+
would split capture across the old and new datapacks or fail outright.
|
|
181
|
+
|
|
182
|
+
## Edge cases
|
|
183
|
+
|
|
184
|
+
- **Multiple pin memories somehow exist** — the user (or a buggy earlier run) created duplicates. Use the most recent (highest `selected_at`); offer to delete the others.
|
|
185
|
+
- **The pinned datapack no longer exists on the server** — the next Meko MCP call will fail with a not-found error. Re-run the skill to pick a new one or `clear` the stale pin.
|
|
186
|
+
- **memory_search times out or fails** — fall back to the server default (omit `datapack_id`) and tell the user *"Couldn't read the active-datapack pin. Using server default for this call."* Don't guess a UUID.
|
|
187
|
+
- **User explicitly overrides for a single call** — pass the user's `datapack_id` for that one call. Do NOT update the pin memory.
|
|
188
|
+
|
|
189
|
+
## Critical: do NOT use other persistence mechanisms
|
|
190
|
+
|
|
191
|
+
Don't write to local files, don't use environment variables, don't ask the user to paste the UUID into every prompt. A single tagged memory is the entire mechanism. Anything else creates drift between what you think is pinned and what `memory_search` will report.
|
|
192
|
+
|
|
193
|
+
## Reference sections
|
|
194
|
+
|
|
195
|
+
| File | What it covers |
|
|
196
|
+
|------|---------------|
|
|
197
|
+
| `references/cookbook.md` | Sample list / search / select / clear transcripts on Desktop |
|
|
198
|
+
| `references/troubleshooting.md` | Pin not recalled, duplicate pins, stale UUID recovery |
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
# Cookbook — meko-select-datapack-desktop
|
|
2
|
+
|
|
3
|
+
Concrete transcripts of the four flows the skill supports on Claude Desktop.
|
|
4
|
+
|
|
5
|
+
## Flow 1 — First pin (no existing pin memory)
|
|
6
|
+
|
|
7
|
+
**User:** `pin prod-research as my active datapack`
|
|
8
|
+
|
|
9
|
+
**Skill:**
|
|
10
|
+
```
|
|
11
|
+
> memory_search(query="meko_active_datapack", agent_id="claude_desktop", limit=1)
|
|
12
|
+
[empty]
|
|
13
|
+
|
|
14
|
+
> datapack_list(scope="read")
|
|
15
|
+
[14 entries returned, filtering by "prod-research"]
|
|
16
|
+
|
|
17
|
+
One match: `prod-research`. Pinning.
|
|
18
|
+
|
|
19
|
+
> memory_add(scope="write",
|
|
20
|
+
text="meko_active_datapack=8b1c…f4a2 name=prod-research selected_at=2026-05-25T18:42:00Z",
|
|
21
|
+
agent_id="claude_desktop",
|
|
22
|
+
conversation_id="<conv-id>",
|
|
23
|
+
metadata='{"type":"active-datapack-pin"}')
|
|
24
|
+
[returns id=mem_abc123]
|
|
25
|
+
|
|
26
|
+
> memory_search(query="meko_active_datapack", agent_id="claude_desktop", limit=1)
|
|
27
|
+
[verifies the row exists]
|
|
28
|
+
|
|
29
|
+
Pinned datapack `prod-research` (`8b1c…f4a2`) for Claude Desktop.
|
|
30
|
+
|
|
31
|
+
Stored as a memory under agent_id="claude_desktop"; persists across sessions
|
|
32
|
+
until you run this skill again with `clear` or `switch`.
|
|
33
|
+
|
|
34
|
+
I'll read this pin via memory_search before each Meko MCP write so the right
|
|
35
|
+
datapack_id flows through automatically.
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Flow 2 — Switch (pin memory already exists)
|
|
39
|
+
|
|
40
|
+
**User:** `switch to the q2-roadmap-deck datapack`
|
|
41
|
+
|
|
42
|
+
**Skill:**
|
|
43
|
+
```
|
|
44
|
+
> memory_search(query="meko_active_datapack", agent_id="claude_desktop", limit=1)
|
|
45
|
+
[returns id=mem_abc123, text="meko_active_datapack=8b1c…f4a2 name=prod-research …"]
|
|
46
|
+
|
|
47
|
+
> datapack_list(scope="read")
|
|
48
|
+
[14 entries returned, filtering by "q2-roadmap-deck"]
|
|
49
|
+
|
|
50
|
+
One match: `q2-roadmap-deck`. Switching pin.
|
|
51
|
+
|
|
52
|
+
> memory_update(scope="write",
|
|
53
|
+
memory_id="mem_abc123",
|
|
54
|
+
text="meko_active_datapack=4c2e…a991 name=q2-roadmap-deck selected_at=2026-05-25T19:05:00Z",
|
|
55
|
+
agent_id="claude_desktop",
|
|
56
|
+
conversation_id="<conv-id>")
|
|
57
|
+
|
|
58
|
+
Switched pin from `prod-research` to `q2-roadmap-deck` (`4c2e…a991`).
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
The `memory_update` is critical here — using `memory_add` again would create a duplicate pin memory.
|
|
62
|
+
|
|
63
|
+
## Flow 3 — Single-datapack auto-select
|
|
64
|
+
|
|
65
|
+
**User:** (first Meko write attempt, no pin yet)
|
|
66
|
+
|
|
67
|
+
**Skill:**
|
|
68
|
+
```
|
|
69
|
+
> memory_search(query="meko_active_datapack", agent_id="claude_desktop", limit=1)
|
|
70
|
+
[empty]
|
|
71
|
+
|
|
72
|
+
> datapack_list(scope="read")
|
|
73
|
+
[1 entry returned]
|
|
74
|
+
|
|
75
|
+
Only one datapack: `meko-local-setup`. Auto-selecting.
|
|
76
|
+
|
|
77
|
+
> memory_add(scope="write",
|
|
78
|
+
text="meko_active_datapack=a17d…cc91 name=meko-local-setup selected_at=…",
|
|
79
|
+
agent_id="claude_desktop",
|
|
80
|
+
conversation_id="<conv-id>",
|
|
81
|
+
metadata='{"type":"active-datapack-pin"}')
|
|
82
|
+
|
|
83
|
+
Pinned datapack `meko-local-setup` (`a17d…cc91`). Run this skill again with
|
|
84
|
+
`clear` to unset.
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
## Flow 4 — Clear
|
|
88
|
+
|
|
89
|
+
**User:** `unpin datapack`
|
|
90
|
+
|
|
91
|
+
**Skill:**
|
|
92
|
+
```
|
|
93
|
+
> memory_search(query="meko_active_datapack", agent_id="claude_desktop", limit=1)
|
|
94
|
+
[returns id=mem_abc123]
|
|
95
|
+
|
|
96
|
+
> memory_delete_by_id(scope="write",
|
|
97
|
+
memory_id="mem_abc123",
|
|
98
|
+
agent_id="claude_desktop",
|
|
99
|
+
conversation_id="<conv-id>")
|
|
100
|
+
|
|
101
|
+
Pin cleared. Subsequent Meko MCP calls will use the server default.
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
If `memory_search` returned empty: *"No pin was set; nothing to clear."*
|
|
105
|
+
|
|
106
|
+
## Flow 5 — Read-the-pin pattern (every Meko-touching turn)
|
|
107
|
+
|
|
108
|
+
This isn't a user-triggered flow — it's the per-turn lookup the skill teaches you to do silently before any Meko MCP write:
|
|
109
|
+
|
|
110
|
+
```
|
|
111
|
+
> memory_search(query="meko_active_datapack", agent_id="claude_desktop",
|
|
112
|
+
conversation_id="<conv-id>", limit=1)
|
|
113
|
+
[returns text="meko_active_datapack=8b1c…f4a2 name=prod-research …"]
|
|
114
|
+
|
|
115
|
+
# Extract UUID after "meko_active_datapack=" → 8b1c…f4a2
|
|
116
|
+
|
|
117
|
+
> memory_add(scope="write", text="…", datapack_id="8b1c…f4a2",
|
|
118
|
+
agent_id="claude_desktop", conversation_id="<conv-id>")
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
Cache the UUID for the rest of the turn — don't call `memory_search` once per Meko tool call.
|