@yugabytedb/meko-mcp 1.2.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.
- package/README.md +59 -25
- package/assets/hooks-handlers/before-submit-prompt.sh +2 -2
- package/assets/hooks-handlers/codex-session-end.sh +78 -0
- package/assets/hooks-handlers/lib/capture.js +366 -152
- package/assets/hooks-handlers/lib/checkpoint-timer.js +67 -13
- package/assets/hooks-handlers/session-end.sh +10 -0
- package/assets/hooks-handlers/session-start.sh +14 -3
- package/assets/hooks-handlers/test_checkpoint_timer.sh +162 -0
- package/assets/scripts/meko-statusline.sh +119 -0
- package/assets/scripts/package-desktop-skill.sh +64 -30
- package/assets/skills/meko-mcp-tools/SKILL.md +84 -86
- package/assets/skills/meko-mcp-tools/references/_sections.md +2 -4
- package/assets/skills/meko-mcp-tools/references/tools-agent-id-conventions.md +29 -25
- package/assets/skills/meko-mcp-tools/references/tools-conversation-dedup.md +5 -7
- package/assets/skills/meko-mcp-tools/references/tools-conversation-reasoning.md +50 -0
- package/assets/skills/meko-mcp-tools/references/tools-cookbook.md +126 -184
- package/assets/skills/meko-mcp-tools/references/tools-datapack-workflow.md +31 -37
- package/assets/skills/meko-mcp-tools/references/tools-known-limitations.md +10 -26
- package/assets/skills/meko-mcp-tools/references/tools-memory-vs-conversation.md +26 -30
- package/assets/skills/meko-mcp-tools/references/tools-overview.md +60 -66
- package/assets/skills/meko-mcp-tools/references/tools-rag-workflow.md +28 -93
- package/assets/skills/meko-mcp-tools/references/tools-troubleshooting.md +5 -99
- package/assets/skills/meko-mcp-tools/references/tools-user-id-conventions.md +9 -8
- package/assets/skills/meko-mcp-tools-desktop/SKILL.md +138 -138
- package/assets/skills/meko-mcp-tools-desktop/desktop/README.md +46 -16
- package/assets/skills/meko-mcp-tools-desktop/references/_sections.md +2 -2
- package/assets/skills/meko-mcp-tools-desktop/references/tools-agent-id-conventions.md +28 -24
- package/assets/skills/meko-mcp-tools-desktop/references/tools-conversation-reasoning.md +50 -0
- package/assets/skills/meko-mcp-tools-desktop/references/tools-cookbook.md +120 -174
- package/assets/skills/meko-mcp-tools-desktop/references/tools-known-limitations.md +16 -22
- package/assets/skills/meko-mcp-tools-desktop/references/tools-memory-vs-conversation.md +28 -34
- package/assets/skills/meko-mcp-tools-desktop/references/tools-overview.md +60 -66
- package/assets/skills/meko-mcp-tools-desktop/references/tools-rag-workflow.md +28 -93
- package/assets/skills/meko-mcp-tools-desktop/references/tools-troubleshooting.md +4 -98
- package/assets/skills/meko-select-datapack-desktop/SKILL.md +208 -0
- package/assets/skills/meko-select-datapack-desktop/references/cookbook.md +121 -0
- package/assets/skills/meko-select-datapack-desktop/references/role-display-future.md +41 -0
- package/assets/skills/meko-select-datapack-desktop/references/troubleshooting.md +66 -0
- package/bin/create-meko-setup.mjs +74 -6
- package/lib/clients/claude-code.mjs +137 -6
- package/lib/clients/claude-desktop.mjs +51 -12
- package/lib/clients/codex.mjs +329 -13
- package/lib/clients/common.mjs +43 -1
- package/lib/clients/cursor.mjs +82 -21
- package/lib/config.mjs +26 -0
- package/lib/detect.mjs +7 -2
- package/lib/installer.mjs +24 -0
- package/lib/mcp-transport.mjs +5 -0
- package/lib/prompt.mjs +1 -1
- package/lib/url-selection.mjs +55 -0
- package/lib/validate.mjs +0 -1
- package/package.json +1 -1
- package/scripts/bundle-assets.mjs +8 -0
- package/assets/skills/meko-mcp-tools/references/tools-db-query-patterns.md +0 -38
- package/assets/skills/meko-mcp-tools/references/tools-scope-permissions.md +0 -75
- package/assets/skills/meko-mcp-tools/references/tools-write-guardrails.md +0 -30
- package/assets/skills/meko-mcp-tools-desktop/references/tools-scope-permissions.md +0 -75
|
@@ -7,13 +7,13 @@ These patterns are extracted from real agent sessions. Follow them to avoid wast
|
|
|
7
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
8
|
2. **Distinguish transient vs persistent failures.** "Connection already closed" is transient (retry once). "Permission denied" is persistent (stop, don't retry).
|
|
9
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`;
|
|
10
|
+
4. **Use your session's `agent_id` consistently on writes.** For Claude Desktop the default is `claude_desktop`; use `meko_agent` when writing cross-project facts. Other clients use `<client>:<repo-basename>` (e.g. `claude_code:meko-mcp-server`). Memory reads and `conversation_list` span all of this user's agents regardless of the value passed; `conversation_get` requires the creating agent's exact value.
|
|
11
11
|
|
|
12
12
|
---
|
|
13
13
|
|
|
14
14
|
## Connection errors: "connection already closed"
|
|
15
15
|
|
|
16
|
-
**Affects:** Memory tools (`memory_add`, `memory_search`, `memory_get_all`) most frequently.
|
|
16
|
+
**Affects:** Memory tools (`memory_add`, `memory_search`, `memory_get_all`) most frequently.
|
|
17
17
|
|
|
18
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
19
|
|
|
@@ -21,87 +21,11 @@ These patterns are extracted from real agent sessions. Follow them to avoid wast
|
|
|
21
21
|
|
|
22
22
|
1. Retry the same call **once**.
|
|
23
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
|
-
3. Direct-SQL fallback **does not apply** on cloud Free Tier (`db_run_read_only_query` returns `{"error": "not_available", "detail": "Free Tier: DB Tools access is not enabled. coming soon."}`). On self-hosted / paid deployments where DB tools are available, inspect memory rows via the multi-tenant schema — tables are namespaced by datapack, not by agent_id. The old `{agent_id}_mem0_collection` per-agent-table layout is gone.
|
|
25
24
|
|
|
26
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.
|
|
27
26
|
|
|
28
27
|
---
|
|
29
28
|
|
|
30
|
-
## RAG pipeline stuck at INIT
|
|
31
|
-
|
|
32
|
-
**Affects:** `knowledgebase_trigger_index_creation` — the build triggers but never completes.
|
|
33
|
-
|
|
34
|
-
**Symptoms:**
|
|
35
|
-
- `knowledgebase_check_index_status` returns empty `pipeline_details` and `pipeline_stats`
|
|
36
|
-
- Documents remain at `INIT` status indefinitely
|
|
37
|
-
- Work queue tasks are `IN_PROGRESS` with `lease_expires_at` in the past
|
|
38
|
-
|
|
39
|
-
**Diagnosis:** Query the work queue directly:
|
|
40
|
-
```
|
|
41
|
-
db_run_read_only_query(scope="read",
|
|
42
|
-
query="SELECT task_type, status, lease_expires_at FROM dist_rag.work_queue WHERE index_name = 'your_index' ORDER BY created_at DESC LIMIT 10")
|
|
43
|
-
```
|
|
44
|
-
|
|
45
|
-
Look for tasks stuck `IN_PROGRESS` with expired leases — these indicate crashed or hung workers.
|
|
46
|
-
|
|
47
|
-
**What to do:**
|
|
48
|
-
|
|
49
|
-
1. Poll status **at most 3 times** with 1-2 minute intervals
|
|
50
|
-
2. If no progress after 3 checks, **stop polling** — the pipeline is stuck
|
|
51
|
-
3. There is **no way to reset or retry stuck tasks via MCP tools**
|
|
52
|
-
4. Creating a new index with a different name (e.g., `_v2`) is a workaround, but if the workers themselves are down, this will also get stuck
|
|
53
|
-
5. Recommend the user check worker logs or restart the pipeline service
|
|
54
|
-
|
|
55
|
-
**Anti-pattern from real sessions:** Agent created indexes `v1`, `v2`, `v3` — all stuck with the same symptoms. Even making the S3 bucket public didn't help. The issue was worker infrastructure, not permissions.
|
|
56
|
-
|
|
57
|
-
---
|
|
58
|
-
|
|
59
|
-
## db_run_write_query guardrail error
|
|
60
|
-
|
|
61
|
-
**Error:** `'dict' object has no attribute 'guardrail_config'`
|
|
62
|
-
|
|
63
|
-
**Affects:** `db_run_write_query` in some deployments.
|
|
64
|
-
|
|
65
|
-
**What to do:**
|
|
66
|
-
|
|
67
|
-
1. Try the call once. If it fails with this specific error, write operations are unavailable in this deployment.
|
|
68
|
-
2. For reads, always use `db_run_read_only_query` (never `db_run_write_query` for SELECT).
|
|
69
|
-
3. Report the issue — it's a server-side bug, not a parameter problem.
|
|
70
|
-
|
|
71
|
-
---
|
|
72
|
-
|
|
73
|
-
## knowledgebase_add_source_to_index failure
|
|
74
|
-
|
|
75
|
-
**Error shape:** `{"error": "not_available", "detail": "Vector index creation is not available on the free tier."}`
|
|
76
|
-
|
|
77
|
-
You're on cloud Free Tier; the ingestion tools are gated off. There is no retry that will succeed. Point the user at the Meko UI's **Add Knowledge** file-upload flow (Datapack → Actions → Add Knowledge) instead.
|
|
78
|
-
|
|
79
|
-
**Error shape:** `{"error": "index_not_found", "detail": "No vector index found with name '...'"}`
|
|
80
|
-
|
|
81
|
-
The `index_name` doesn't exist in this datapack's `dist_rag.vector_indexes` table. Either you're targeting the wrong datapack (check `datapack_id`), or the index hasn't been created yet — call `knowledgebase_trigger_index_creation` first.
|
|
82
|
-
|
|
83
|
-
**Error shape:** tool returns `"build_triggered"` but `knowledgebase_check_index_status` shows documents stuck at `INIT` for >5 minutes.
|
|
84
|
-
|
|
85
|
-
Most common cause on self-hosted deployments: the worker can't reach the S3 bucket. `S3BucketCrawler()` uses boto3's default credential chain — check `AWS_ACCESS_KEY_ID` / `AWS_SECRET_ACCESS_KEY` / IAM role / `~/.aws/credentials` on the worker host, not on the MCP server. Second cause: the URI isn't `s3://`-prefixed (`aws_source_processor.py` rejects other schemes with `ValueError("Invalid source URI")` async).
|
|
86
|
-
|
|
87
|
-
**Historical note:** the old `r_index_name` vs `r_index_id` parameter-mismatch bug is fixed on main — the MCP tool now resolves `index_name → index_id` internally via a `SELECT id FROM dist_rag.vector_indexes WHERE index_name = %s` step. Older docs referencing this bug are stale.
|
|
88
|
-
|
|
89
|
-
---
|
|
90
|
-
|
|
91
|
-
## Scope parameter errors
|
|
92
|
-
|
|
93
|
-
**Error:** `Insufficient scope: 'all'. This tool requires 'read' or higher.`
|
|
94
|
-
|
|
95
|
-
The only valid scope values are: `"read"`, `"write"`, `"admin"`.
|
|
96
|
-
|
|
97
|
-
- Use `"read"` for all read operations (default choice)
|
|
98
|
-
- Use `"write"` for inserts, updates, creates, memory writes
|
|
99
|
-
- Use `"admin"` only for destructive deletes
|
|
100
|
-
|
|
101
|
-
**Never use:** `"all"`, `"readwrite"`, `"rw"`, or any other value.
|
|
102
|
-
|
|
103
|
-
---
|
|
104
|
-
|
|
105
29
|
## agent_id errors
|
|
106
30
|
|
|
107
31
|
On the Cloud multi-tenant schema, `agent_id` is a TEXT column value — not a PostgreSQL identifier — so arbitrary strings are accepted.
|
|
@@ -116,7 +40,7 @@ Fix: always pass a concrete non-empty `agent_id`. For Claude Desktop use `agent_
|
|
|
116
40
|
|
|
117
41
|
### "My reads return fewer results than I expected"
|
|
118
42
|
|
|
119
|
-
`memory_search` and `memory_get_all`
|
|
43
|
+
`memory_search` and `memory_get_all` do not filter by `agent_id`: one call returns this user's memories across every agent. If results seem thin, check the `datapack_id`, confirm the write landed, and remember that mem0 extraction can be lossy. `conversation_get` is agent-owned and requires the exact creating `agent_id`; `conversation_list` is not agent-filtered.
|
|
120
44
|
|
|
121
45
|
### "I'm seeing rows tagged with legacy agent_id values"
|
|
122
46
|
|
|
@@ -124,32 +48,14 @@ Pre-existing data may be tagged `"agent"`, `"claude_code"`, `"cursor:<slug>"`, o
|
|
|
124
48
|
|
|
125
49
|
---
|
|
126
50
|
|
|
127
|
-
## Permission denied on data tables
|
|
128
|
-
|
|
129
|
-
**Error:** `permission denied for table customer_complaints`
|
|
130
|
-
|
|
131
|
-
**Why:** The MCP database user may not have read access to all tables, particularly data tables created by the provisioning system within a datapack.
|
|
132
|
-
|
|
133
|
-
**What to do:**
|
|
134
|
-
|
|
135
|
-
1. This is a server-side configuration issue — not fixable via MCP tools.
|
|
136
|
-
2. Don't retry. Don't try different query formulations.
|
|
137
|
-
3. Use `db_summarize_database` to see which tables you CAN access.
|
|
138
|
-
4. Report the permission gap to the Meko admin.
|
|
139
|
-
|
|
140
|
-
---
|
|
141
|
-
|
|
142
51
|
## Safe-to-retry vs not
|
|
143
52
|
|
|
144
53
|
| Tool | Safe to retry? | Why |
|
|
145
54
|
|------|---------------|-----|
|
|
146
|
-
| All
|
|
55
|
+
| All read-only tools | Yes | Reads are idempotent |
|
|
147
56
|
| `memory_add` | Yes (once) | Mem0 has dedup logic |
|
|
148
57
|
| `memory_update` | Yes (once) | Overwrites same ID |
|
|
149
58
|
| `memory_delete_by_id` | Yes | Deleting already-deleted is a no-op |
|
|
150
|
-
| `db_run_write_query` (INSERT) | **No** | May double-insert rows |
|
|
151
|
-
| `db_run_write_query` (CREATE TABLE) | **No** | "Table already exists" error |
|
|
152
|
-
| `knowledgebase_trigger_index_creation` | **No** | Creates duplicate indexes |
|
|
153
59
|
| `conversation_create` | **No** | Creates duplicate conversations |
|
|
154
60
|
| `conversation_add_message` with `seed` | Yes | Seed-based dedup prevents duplicates |
|
|
155
61
|
| `conversation_add_message` without `seed` | **No** | Creates duplicate messages |
|
|
@@ -0,0 +1,208 @@
|
|
|
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 the Acme datapack",
|
|
7
|
+
"list my datapacks", "which datapack am I on", "pin Acme", 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.2.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, conversation_add_message, artifact_put, etc.), if you don't already know the active pin from this turn's earlier work:
|
|
46
|
+
|
|
47
|
+
```
|
|
48
|
+
memory_search(
|
|
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(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(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`, `account_id`, and `grant`.
|
|
80
|
+
|
|
81
|
+
`grant` is the caller's actual authorization on the datapack — one of
|
|
82
|
+
`"owner"`, `"maintainer"`, `"contributor"`, `"viewer"`. Display it verbatim in
|
|
83
|
+
the Role column. Do not hardcode "Owner", do not invent or normalize the value
|
|
84
|
+
(render `"maintainer"` as `maintainer`, not `Maintainer`). The deployed
|
|
85
|
+
response is the source of truth — see `references/role-display-future.md` for
|
|
86
|
+
the taxonomy.
|
|
87
|
+
|
|
88
|
+
If the response has zero entries, tell the user: *"You don't have any datapacks yet. Run `datapack_create(name='<name>')` to make one, or visit the Meko Cloud console."* Stop here.
|
|
89
|
+
|
|
90
|
+
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).
|
|
91
|
+
|
|
92
|
+
### 2. Render the table
|
|
93
|
+
|
|
94
|
+
For 2+ datapacks, render a numbered table. **Page size 10.** Default sort: `created_at DESC` (newest first).
|
|
95
|
+
|
|
96
|
+
```
|
|
97
|
+
Your datapacks (showing 1-10 of 14):
|
|
98
|
+
|
|
99
|
+
# Name Role Created Status Active?
|
|
100
|
+
1 meko-local-setup owner 2026-04-30 ready ← (pinned)
|
|
101
|
+
2 meko_default_datapack owner 2026-04-30 ready
|
|
102
|
+
3 team-onboarding maintainer 2026-04-08 ready
|
|
103
|
+
4 q2-roadmap viewer 2026-03-22 ready
|
|
104
|
+
…
|
|
105
|
+
|
|
106
|
+
Reply with: a number (1-10) to pin · a substring to search · `next` / `prev` to page
|
|
107
|
+
· `clear` to unset · `cancel` to leave the current pin alone
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
The **Role** column shows each datapack's `grant` value verbatim (`owner`,
|
|
111
|
+
`maintainer`, `contributor`, `viewer`). Never hardcode "Owner" — shared
|
|
112
|
+
datapacks legitimately carry other grants, and misreporting them (e.g. showing
|
|
113
|
+
a `maintainer` grant as "Owner") misleads the user about their own access.
|
|
114
|
+
|
|
115
|
+
Mark the currently-pinned row with `← (pinned)` based on the `memory_search` result (if any).
|
|
116
|
+
|
|
117
|
+
### 3. Parse the user's reply
|
|
118
|
+
|
|
119
|
+
- **Integer in range** → that row is the choice.
|
|
120
|
+
- **Substring** → re-render filtered. If it narrows to one row, that's the choice.
|
|
121
|
+
- **`next` / `prev`** → re-render next/previous page.
|
|
122
|
+
- **`cancel`** → leave any existing pin in place; print *"Cancelled. Active datapack unchanged."* Stop.
|
|
123
|
+
- **`clear` / `none` / `unpin`** → see step 4's clear path.
|
|
124
|
+
- **Unrecognized** → re-prompt with the legend.
|
|
125
|
+
|
|
126
|
+
### 4. Persist
|
|
127
|
+
|
|
128
|
+
**On first pin (no existing pin memory):**
|
|
129
|
+
|
|
130
|
+
```
|
|
131
|
+
memory_add(
|
|
132
|
+
text="meko_active_datapack=<uuid> name=<name> selected_at=<iso8601>",
|
|
133
|
+
agent_id="claude_desktop",
|
|
134
|
+
conversation_id="<this conversation's id>",
|
|
135
|
+
metadata='{"type":"active-datapack-pin"}')
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
Verify the write with `memory_search` (the standard Meko verify-after-write rule from `meko-mcp-tools-desktop`). Capture the returned memory `id`.
|
|
139
|
+
|
|
140
|
+
**On switch (existing pin memory found):**
|
|
141
|
+
|
|
142
|
+
```
|
|
143
|
+
memory_update(
|
|
144
|
+
memory_id="<existing pin id>",
|
|
145
|
+
text="meko_active_datapack=<new uuid> name=<new name> selected_at=<iso8601>",
|
|
146
|
+
agent_id="claude_desktop",
|
|
147
|
+
conversation_id="<this conversation's id>")
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
Always update — never `memory_add` a second pin. Two pin memories will produce ambiguous reads.
|
|
151
|
+
|
|
152
|
+
**On clear:**
|
|
153
|
+
|
|
154
|
+
```
|
|
155
|
+
memory_delete_by_id(
|
|
156
|
+
memory_id="<existing pin id>",
|
|
157
|
+
agent_id="claude_desktop",
|
|
158
|
+
conversation_id="<this conversation's id>")
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
If `memory_search` returned no pin, there's nothing to delete — print *"No pin was set; nothing to clear."* and stop.
|
|
162
|
+
|
|
163
|
+
**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:
|
|
164
|
+
|
|
165
|
+
- **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."*
|
|
166
|
+
- **Option B — start default-datapack capture immediately.** Create a **new** conversation with no `datapack_id` (`conversation_create(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."*
|
|
167
|
+
|
|
168
|
+
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.
|
|
169
|
+
|
|
170
|
+
### 5. Confirm
|
|
171
|
+
|
|
172
|
+
```
|
|
173
|
+
Pinned datapack `<name>` (`<uuid>`) for Claude Desktop.
|
|
174
|
+
|
|
175
|
+
This is stored as a memory under agent_id="claude_desktop". It will persist
|
|
176
|
+
across sessions until you run this skill again with `clear` (or `switch` to
|
|
177
|
+
a different datapack).
|
|
178
|
+
|
|
179
|
+
I'll read this pin via `memory_search` before each Meko MCP write so the
|
|
180
|
+
right `datapack_id` flows through automatically.
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
**Then start a fresh conversation for capture in the selected datapack.** The
|
|
184
|
+
temporary selection conversation from step 1 belongs to the datapack that was
|
|
185
|
+
active when it was created and cannot be moved. For subsequent capture this
|
|
186
|
+
session, call `conversation_create(agent_id="claude_desktop",
|
|
187
|
+
datapack_id="<the newly pinned uuid>", title="<topic>")` and post turns
|
|
188
|
+
(`conversation_add_message`) to *that* conversation with the same
|
|
189
|
+
`datapack_id`. Do not keep posting to the selection conversation — doing so
|
|
190
|
+
would split capture across the old and new datapacks or fail outright.
|
|
191
|
+
|
|
192
|
+
## Edge cases
|
|
193
|
+
|
|
194
|
+
- **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.
|
|
195
|
+
- **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.
|
|
196
|
+
- **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.
|
|
197
|
+
- **User explicitly overrides for a single call** — pass the user's `datapack_id` for that one call. Do NOT update the pin memory.
|
|
198
|
+
|
|
199
|
+
## Critical: do NOT use other persistence mechanisms
|
|
200
|
+
|
|
201
|
+
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.
|
|
202
|
+
|
|
203
|
+
## Reference sections
|
|
204
|
+
|
|
205
|
+
| File | What it covers |
|
|
206
|
+
|------|---------------|
|
|
207
|
+
| `references/cookbook.md` | Sample list / search / select / clear transcripts on Desktop |
|
|
208
|
+
| `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()
|
|
15
|
+
[14 entries returned, filtering by "prod-research"]
|
|
16
|
+
|
|
17
|
+
One match: `prod-research`. Pinning.
|
|
18
|
+
|
|
19
|
+
> memory_add(
|
|
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()
|
|
48
|
+
[14 entries returned, filtering by "q2-roadmap-deck"]
|
|
49
|
+
|
|
50
|
+
One match: `q2-roadmap-deck`. Switching pin.
|
|
51
|
+
|
|
52
|
+
> memory_update(
|
|
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()
|
|
73
|
+
[1 entry returned]
|
|
74
|
+
|
|
75
|
+
Only one datapack: `meko-local-setup`. Auto-selecting.
|
|
76
|
+
|
|
77
|
+
> memory_add(
|
|
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(
|
|
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(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.
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# Role display — current state
|
|
2
|
+
|
|
3
|
+
## Today: render `grant` verbatim
|
|
4
|
+
|
|
5
|
+
The deployed Meko `GET /datapacks` response includes a `grant` field on every datapack. Possible values (per maintainer guidance, 2026-05-26):
|
|
6
|
+
|
|
7
|
+
- `"owner"` — datapacks the caller created.
|
|
8
|
+
- `"maintainer"` — write access to a shared datapack including memories AND collective learnings/knowledge.
|
|
9
|
+
- `"contributor"` — write access to a shared datapack: can generate own memories. (Cannot promote / publish collective learnings — that's the maintainer's job.)
|
|
10
|
+
- `"viewer"` — read-only on a shared datapack.
|
|
11
|
+
|
|
12
|
+
Use the field directly in the **Role** column:
|
|
13
|
+
|
|
14
|
+
```
|
|
15
|
+
# Name Role Created Active?
|
|
16
|
+
1 prod-research owner 2026-04-12 ← (pinned)
|
|
17
|
+
2 team-onboarding contributor 2026-04-08
|
|
18
|
+
3 q2-roadmap viewer 2026-03-22
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Do not invent values, do not normalize the casing, do not display `"Owner"` if the field says `"owner"`. The deployed schema is the source of truth.
|
|
22
|
+
|
|
23
|
+
Note that the upstream Go source (the `Datapack` struct in `api_server/internal/models/models.go` of the `meko` API-server repo) does NOT declare `grant` — the deployed server enriches the response beyond what the public Go code lists. Don't rely on the public struct for the wire schema; trust the actual response.
|
|
24
|
+
|
|
25
|
+
## Other fields the live response includes
|
|
26
|
+
|
|
27
|
+
Beyond the columns the skill renders by default, `datapack_list` returns counts that may be useful in some flows:
|
|
28
|
+
|
|
29
|
+
- `memory_count` — total memories the caller has under this datapack (per `(user_id, agent_id)` scoping).
|
|
30
|
+
- `knowledge_count` — knowledge-base entries on the datapack.
|
|
31
|
+
- `learnings_count` — promoted-to-shared memories on the datapack.
|
|
32
|
+
|
|
33
|
+
These aren't in the spec column set. Don't add them silently. If the user asks for counts, render them on request — and read the numbers from the live response, never invent them.
|
|
34
|
+
|
|
35
|
+
## Sharing UI vs API state
|
|
36
|
+
|
|
37
|
+
The Cloud console "Share <datapack>" page (`meko_ui/src/features/datapacks/pages/DatapackSharePage.tsx`) shows interactive controls with "Coming Soon" overlays on a few specific actions (e.g. invite-by-email link sharing, transfer-ownership). Those overlays mean *those specific UI affordances* aren't shipped — NOT that the underlying `grant`/sharing model is absent. Contributor/maintainer/viewer grants are functional in the data layer today; only the user-facing self-serve invite flow is gated.
|
|
38
|
+
|
|
39
|
+
## Why the skill ships without Mine / Shared / All filter tabs
|
|
40
|
+
|
|
41
|
+
The tagged pin memory (re-read via `memory_search` before each Meko write) delivers the user's actual ask ("don't make me remember a UUID"). Filter tabs are useful when the response is genuinely mixed-grant; for users with only owner-grant rows they're decorative. We add tabs when there's evidence users with mixed-grant responses want them.
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# Troubleshooting — meko-select-datapack-desktop
|
|
2
|
+
|
|
3
|
+
## Symptom: I pinned a datapack but the next Meko call doesn't use it
|
|
4
|
+
|
|
5
|
+
**Likely causes**
|
|
6
|
+
|
|
7
|
+
1. **You forgot the per-turn `memory_search`.** Desktop has no SessionStart hook, so the skill teaches you to read the pin yourself at the top of every Meko-touching turn. If you skip that lookup, you'll send Meko calls with no `datapack_id` and the server resolves the default. Add the lookup; cache the result for the rest of the turn.
|
|
8
|
+
2. **You used `agent_id="meko_agent"` for the pin write or read.** The pin lives under `agent_id="claude_desktop"`, exclusively. Cross-project facts go under `meko_agent`, but the pin is a Desktop-specific preference and should stay scoped.
|
|
9
|
+
3. **The pin write failed silently.** Always verify-after-write — call `memory_search` for `meko_active_datapack` immediately after `memory_add` and confirm the row appears. If it doesn't, the write was lost (latency, server error, wrong scope) and the pin doesn't actually exist.
|
|
10
|
+
|
|
11
|
+
## Symptom: `memory_search` returns multiple pin memories
|
|
12
|
+
|
|
13
|
+
You (or an earlier run) created duplicates by using `memory_add` instead of `memory_update` on a switch. Resolution:
|
|
14
|
+
|
|
15
|
+
1. Pick the most recent (highest `selected_at` in the text body).
|
|
16
|
+
2. `memory_delete_by_id` the others.
|
|
17
|
+
3. From now on, switch via `memory_update` on the surviving id — never `memory_add`.
|
|
18
|
+
|
|
19
|
+
The cookbook's Flow 2 demonstrates the correct switch path.
|
|
20
|
+
|
|
21
|
+
## Symptom: A pinned datapack returns "not found" when used
|
|
22
|
+
|
|
23
|
+
The pin became stale — the datapack was deleted in another client. Tell the user:
|
|
24
|
+
|
|
25
|
+
```
|
|
26
|
+
The pinned datapack `<name>` (`<id>`) no longer exists on the server.
|
|
27
|
+
Run `meko-select-datapack-desktop` to pick a fresh one, or `clear` to unpin.
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Then either re-run the skill or delete the pin memory. Do not silently fall back to the default — the user explicitly asked for a specific datapack.
|
|
31
|
+
|
|
32
|
+
## Symptom: Substring search matches multiple datapacks
|
|
33
|
+
|
|
34
|
+
Never auto-pick when there's ambiguity. Re-render just the matching rows numbered from 1, and ask the user to pick a number from the filtered subset. Same as the Claude Code variant.
|
|
35
|
+
|
|
36
|
+
## Symptom: `datapack_list` returns an empty array
|
|
37
|
+
|
|
38
|
+
The user has zero datapacks. Print:
|
|
39
|
+
|
|
40
|
+
```
|
|
41
|
+
You don't have any datapacks yet. Create one with:
|
|
42
|
+
|
|
43
|
+
datapack_create(name="<your-datapack-name>")
|
|
44
|
+
|
|
45
|
+
Or visit the Meko Cloud console (Datapacks → New datapack).
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Stop. Don't `memory_add` an empty pin.
|
|
49
|
+
|
|
50
|
+
## Symptom: User typed `cancel` after the table rendered
|
|
51
|
+
|
|
52
|
+
Leave the existing pin memory alone. Print:
|
|
53
|
+
|
|
54
|
+
```
|
|
55
|
+
Cancelled. Active datapack unchanged.
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Do NOT delete on `cancel` — that's `clear`'s job.
|
|
59
|
+
|
|
60
|
+
## Symptom: `memory_search` for the pin times out
|
|
61
|
+
|
|
62
|
+
Memory tools are slow on prod (search 2-6s observed). If the search exceeds a reasonable budget, fall back to the server default for that single call and tell the user *"Couldn't read the active-datapack pin within budget — using server default for this Meko call."* Don't guess a UUID; don't silently retry indefinitely.
|
|
63
|
+
|
|
64
|
+
## Symptom: The pin survived a `claude_desktop` profile reset / app reinstall
|
|
65
|
+
|
|
66
|
+
That's expected — the pin is a server-side memory, not local state. To explicitly forget across reinstalls, run the skill with `clear` BEFORE wiping local state, or `memory_delete_by_id` the pin row directly.
|