@clawpify/skills 1.0.5 → 1.0.6

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/clawpify/SKILL.md CHANGED
@@ -1,134 +1,36 @@
1
1
  ---
2
2
  name: clawpify
3
3
  description: Query and manage Shopify stores via GraphQL Admin API. Use for products, orders, customers, inventory, discounts, and all Shopify data operations.
4
- dependencies:
5
- - Tool: shopify_graphql (from MCP server or custom function)
6
4
  ---
7
5
 
8
6
  # Shopify GraphQL Admin API
9
7
 
10
- A comprehensive skill for interacting with Shopify's GraphQL Admin API. This skill enables Claude to query and manage all aspects of Shopify store data.
11
-
12
- ## When to Use This Skill
13
-
14
- Use this skill when the user asks about:
15
- - Products (list, search, create, update, delete)
16
- - Orders (view, cancel, fulfill)
17
- - Customers (list, create, update)
18
- - Inventory (check levels, adjust quantities)
19
- - Discounts (create codes, manage promotions)
20
- - Any other Shopify store operations
21
-
22
- ## Critical Operations Requiring Permission
23
-
24
- IMPORTANT: Before executing any of the following operations, you MUST ask for explicit user permission:
25
-
26
- - Refunds: Create refunds (permanent financial transactions)
27
- - Order Cancellations: Cancel orders (may trigger refunds)
28
- - Gift Card Deactivation: Permanently disable gift cards
29
- - Inventory Adjustments: Modify stock levels
30
- - Product Deletions: Permanently remove products
31
- - Discount Activations: Change pricing for customers
32
-
33
- Always show what will be changed and wait for user confirmation.
34
-
35
8
  ## How to Use
36
9
 
37
- 1. Use the `shopify_graphql` tool to execute queries
38
- 2. Check for `errors` (GraphQL issues) and `userErrors` (validation issues)
39
- 3. Use pagination with `first`/`after` for large result sets
10
+ 1. Use `load_skill_reference` to load the relevant reference FIRST
11
+ 2. Use `shopify_graphql` to execute queries based on the loaded reference
12
+ 3. Check for `errors` and `userErrors` in responses
40
13
  4. Format all IDs as: `gid://shopify/Resource/123`
41
14
 
42
- ## Available References
43
-
44
- For detailed patterns and examples, refer to the reference documents:
45
- - products.md - Products and variants management
46
- - orders.md - Order operations
47
- - customers.md - Customer management
48
- - inventory.md - Inventory and locations
49
- - discounts.md - Discount codes and promotions
50
- - collections.md - Product collections
51
- - fulfillments.md - Order fulfillment and shipping
52
- - refunds.md - Process refunds
53
- - draft-orders.md - Draft order creation
54
- - gift-cards.md - Gift card management
55
- - webhooks.md - Event subscriptions
56
- - locations.md - Store locations
57
- - marketing.md - Marketing activities
58
- - markets.md - Multi-market setup
59
- - menus.md - Navigation menus
60
- - metafields.md - Custom data fields
61
- - pages.md - Store pages
62
- - blogs.md - Blog management
63
- - files.md - File uploads
64
- - shipping.md - Shipping configuration
65
- - shop.md - Store information
66
- - subscriptions.md - Subscription management
67
- - translations.md - Content translations
68
- - segments.md - Customer segments
69
- - bulk-operations.md - Bulk data operations
70
-
71
- ## Quick Examples
72
-
73
- ### List Recent Orders
74
- ```graphql
75
- query {
76
- orders(first: 10, sortKey: CREATED_AT, reverse: true) {
77
- nodes {
78
- id
79
- name
80
- totalPriceSet {
81
- shopMoney { amount currencyCode }
82
- }
83
- customer { displayName }
84
- }
85
- }
86
- }
87
- ```
88
-
89
- ### Search Products
90
- ```graphql
91
- query {
92
- products(first: 10, query: "title:*shirt* AND status:ACTIVE") {
93
- nodes {
94
- id
95
- title
96
- status
97
- }
98
- }
99
- }
100
- ```
15
+ ## Critical Operations Requiring Permission
101
16
 
102
- ### Check Inventory
103
- ```graphql
104
- query GetInventory($id: ID!) {
105
- inventoryItem(id: $id) {
106
- id
107
- inventoryLevels(first: 5) {
108
- nodes {
109
- quantities(names: ["available"]) {
110
- name
111
- quantity
112
- }
113
- location { name }
114
- }
115
- }
116
- }
117
- }
118
- ```
17
+ IMPORTANT: Before executing any of the following, you MUST ask for explicit user permission:
119
18
 
120
- ## Error Handling
19
+ - Refunds, order cancellations, gift card deactivation
20
+ - Inventory adjustments, product deletions, discount activations
121
21
 
122
- Always check responses:
123
- - `errors` array = GraphQL syntax issues
124
- - `userErrors` in mutations = validation problems
22
+ Always show what will be changed and wait for confirmation.
125
23
 
126
- ## Best Practices
24
+ ## Available References
127
25
 
128
- 1. Request only needed fields to optimize response size
129
- 2. Use pagination for lists that may grow
130
- 3. Check userErrors in all mutation responses
131
- 4. Ask permission before dangerous operations
132
- 5. Format results clearly for the user
133
- 6. Use bulk operations for large data exports/imports
134
- 7. Handle rate limits with exponential backoff
26
+ Load the reference for your domain using `load_skill_reference` before writing queries:
27
+
28
+ **Store**: [shop](reference/shop.md) | [locations](reference/locations.md) | [markets](reference/markets.md)
29
+ **Catalog**: [products](reference/products.md) | [collections](reference/collections.md) | [inventory](reference/inventory.md)
30
+ **Sales**: [orders](reference/orders.md) | [draft-orders](reference/draft-orders.md) | [fulfillments](reference/fulfillments.md) | [refunds](reference/refunds.md)
31
+ **Customers**: [customers](reference/customers.md) | [segments](reference/segments.md) | [gift-cards](reference/gift-cards.md)
32
+ **Pricing**: [discounts](reference/discounts.md) | [subscriptions](reference/subscriptions.md)
33
+ **Content**: [pages](reference/pages.md) | [blogs](reference/blogs.md) | [menus](reference/menus.md) | [translations](reference/translations.md) | [files](reference/files.md)
34
+ **Custom data**: [metafields](reference/metafields.md)
35
+ **Automation**: [webhooks](reference/webhooks.md) | [bulk-operations](reference/bulk-operations.md)
36
+ **Growth**: [marketing](reference/marketing.md) | [shipping](reference/shipping.md)
@@ -1 +1 @@
1
- {"version":3,"file":"agent.d.ts","sourceRoot":"","sources":["../src/agent.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"agent.d.ts","sourceRoot":"","sources":["../src/agent.ts"],"names":[],"mappings":"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"}
package/dist/agent.js CHANGED
@@ -1,3 +1,51 @@
1
+ // src/skills.ts
2
+ import { readdir, readFile } from "node:fs/promises";
3
+ import { join } from "node:path";
4
+ import { fileURLToPath } from "node:url";
5
+ async function loadSkills(customDir) {
6
+ const baseDir = customDir ?? join(fileURLToPath(import.meta.url), "..", "..", "clawpify");
7
+ const skillParts = [];
8
+ await collectMarkdown(baseDir, skillParts);
9
+ return skillParts.join(`
10
+
11
+ ---
12
+
13
+ `);
14
+ }
15
+ async function loadSkillMetadata(customDir) {
16
+ const baseDir = customDir ?? join(fileURLToPath(import.meta.url), "..", "..", "clawpify");
17
+ const skillPath = join(baseDir, "SKILL.md");
18
+ return readFile(skillPath, "utf-8");
19
+ }
20
+ async function loadSkillReference(name, customDir) {
21
+ const baseDir = customDir ?? join(fileURLToPath(import.meta.url), "..", "..", "clawpify");
22
+ const refPath = join(baseDir, "references", name.endsWith(".md") ? name : `${name}.md`);
23
+ return readFile(refPath, "utf-8");
24
+ }
25
+ async function listSkillReferences(customDir) {
26
+ const baseDir = customDir ?? join(fileURLToPath(import.meta.url), "..", "..", "clawpify");
27
+ const refDir = join(baseDir, "references");
28
+ const entries = await readdir(refDir);
29
+ return entries.filter((e) => e.endsWith(".md")).map((e) => e.replace(".md", ""));
30
+ }
31
+ async function collectMarkdown(dir, parts) {
32
+ let entries;
33
+ try {
34
+ entries = await readdir(dir, { withFileTypes: true });
35
+ } catch {
36
+ return;
37
+ }
38
+ for (const entry of entries) {
39
+ const fullPath = join(dir, entry.name);
40
+ if (entry.isDirectory()) {
41
+ await collectMarkdown(fullPath, parts);
42
+ } else if (entry.name.endsWith(".md")) {
43
+ const content = await readFile(fullPath, "utf-8");
44
+ parts.push(content);
45
+ }
46
+ }
47
+ }
48
+
1
49
  // src/agent.ts
2
50
  import Anthropic from "@anthropic-ai/sdk";
3
51
  var DEFAULT_SYSTEM_INSTRUCTION = "You're Clawpify. You help run a Shopify store. The merchant texts you to get stuff done";
@@ -19,6 +67,20 @@ var SHOPIFY_GRAPHQL_TOOL = {
19
67
  required: ["query"]
20
68
  }
21
69
  };
70
+ var LOAD_SKILL_REFERENCE_TOOL = {
71
+ name: "load_skill_reference",
72
+ description: "Load a Shopify GraphQL reference document for a specific domain. Available: products, orders, customers, inventory, discounts, collections, fulfillments, refunds, draft-orders, gift-cards, webhooks, locations, marketing, markets, menus, metafields, pages, blogs, files, shipping, shop, subscriptions, translations, segments, bulk-operations. Use this BEFORE writing GraphQL queries to get the correct syntax.",
73
+ input_schema: {
74
+ type: "object",
75
+ properties: {
76
+ reference: {
77
+ type: "string",
78
+ description: "Name of the reference to load (e.g. 'orders', 'products', 'inventory')"
79
+ }
80
+ },
81
+ required: ["reference"]
82
+ }
83
+ };
22
84
  var DEFAULT_PRICING = {
23
85
  inputPerMillion: 3,
24
86
  outputPerMillion: 15,
@@ -98,8 +160,8 @@ class ShopifyAgent {
98
160
  }
99
161
  registerPlugin(plugin) {
100
162
  const name = plugin.tool.name;
101
- if (name === "shopify_graphql") {
102
- throw new Error(`Cannot register plugin with reserved tool name "shopify_graphql"`);
163
+ if (name === "shopify_graphql" || name === "load_skill_reference") {
164
+ throw new Error(`Cannot register plugin with reserved tool name "${name}"`);
103
165
  }
104
166
  if (this.plugins.has(name)) {
105
167
  throw new Error(`Plugin with tool name "${name}" is already registered`);
@@ -119,6 +181,7 @@ class ShopifyAgent {
119
181
  buildTools() {
120
182
  const allTools = [
121
183
  SHOPIFY_GRAPHQL_TOOL,
184
+ LOAD_SKILL_REFERENCE_TOOL,
122
185
  ...[...this.plugins.values()].map((p) => p.tool)
123
186
  ];
124
187
  if (allTools.length > 0) {
@@ -156,6 +219,17 @@ class ShopifyAgent {
156
219
  return { content: content2, isError: true };
157
220
  }
158
221
  }
222
+ if (name === "load_skill_reference") {
223
+ try {
224
+ const content2 = await loadSkillReference(input.reference);
225
+ await safeHook(this.hooks.onToolResult, name, content2, false);
226
+ return { content: content2, isError: false };
227
+ } catch (error) {
228
+ const content2 = `Error: ${error instanceof Error ? error.message : String(error)}`;
229
+ await safeHook(this.hooks.onToolResult, name, content2, true);
230
+ return { content: content2, isError: true };
231
+ }
232
+ }
159
233
  if (this.plugins.has(name)) {
160
234
  const plugin = this.plugins.get(name);
161
235
  try {
package/dist/index.d.ts CHANGED
@@ -39,6 +39,6 @@ export { ShopifyAgent, DEFAULT_SYSTEM_INSTRUCTION } from "./agent";
39
39
  export type { AgentConfig, AgentHooks, AgentPlugin, ChatResult, ModelPricing, StreamEvent, ThinkingConfig, TokenUsage, } from "./agent";
40
40
  export { InMemoryStore } from "./memory";
41
41
  export type { MemoryStore } from "./memory";
42
- export { loadSkills } from "./skills";
42
+ export { loadSkills, loadSkillMetadata, loadSkillReference, listSkillReferences, } from "./skills";
43
43
  export type { ShopifyClientConfig, GraphQLResponse } from "./shopify";
44
44
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AAGH,OAAO,EAAE,aAAa,EAAE,mBAAmB,EAAE,MAAM,WAAW,CAAC;AAG/D,OAAO,EACL,yBAAyB,EACzB,cAAc,EACd,KAAK,mBAAmB,EACxB,KAAK,uBAAuB,GAC7B,MAAM,QAAQ,CAAC;AAGhB,OAAO,EAAE,YAAY,EAAE,0BAA0B,EAAE,MAAM,SAAS,CAAC;AACnE,YAAY,EACV,WAAW,EACX,UAAU,EACV,WAAW,EACX,UAAU,EACV,YAAY,EACZ,WAAW,EACX,cAAc,EACd,UAAU,GACX,MAAM,SAAS,CAAC;AAGjB,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,YAAY,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAG5C,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAGtC,YAAY,EAAE,mBAAmB,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AAGH,OAAO,EAAE,aAAa,EAAE,mBAAmB,EAAE,MAAM,WAAW,CAAC;AAG/D,OAAO,EACL,yBAAyB,EACzB,cAAc,EACd,KAAK,mBAAmB,EACxB,KAAK,uBAAuB,GAC7B,MAAM,QAAQ,CAAC;AAGhB,OAAO,EAAE,YAAY,EAAE,0BAA0B,EAAE,MAAM,SAAS,CAAC;AACnE,YAAY,EACV,WAAW,EACX,UAAU,EACV,WAAW,EACX,UAAU,EACV,YAAY,EACZ,WAAW,EACX,cAAc,EACd,UAAU,GACX,MAAM,SAAS,CAAC;AAGjB,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,YAAY,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAG5C,OAAO,EACL,UAAU,EACV,iBAAiB,EACjB,kBAAkB,EAClB,mBAAmB,GACpB,MAAM,UAAU,CAAC;AAGlB,YAAY,EAAE,mBAAmB,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC"}
package/dist/index.js CHANGED
@@ -87,6 +87,54 @@ async function createAuthenticatedConfig() {
87
87
  ` + " - SHOPIFY_CLIENT_ID and SHOPIFY_CLIENT_SECRET (OAuth client credentials)");
88
88
  }
89
89
 
90
+ // src/skills.ts
91
+ import { readdir, readFile } from "node:fs/promises";
92
+ import { join } from "node:path";
93
+ import { fileURLToPath } from "node:url";
94
+ async function loadSkills(customDir) {
95
+ const baseDir = customDir ?? join(fileURLToPath(import.meta.url), "..", "..", "clawpify");
96
+ const skillParts = [];
97
+ await collectMarkdown(baseDir, skillParts);
98
+ return skillParts.join(`
99
+
100
+ ---
101
+
102
+ `);
103
+ }
104
+ async function loadSkillMetadata(customDir) {
105
+ const baseDir = customDir ?? join(fileURLToPath(import.meta.url), "..", "..", "clawpify");
106
+ const skillPath = join(baseDir, "SKILL.md");
107
+ return readFile(skillPath, "utf-8");
108
+ }
109
+ async function loadSkillReference(name, customDir) {
110
+ const baseDir = customDir ?? join(fileURLToPath(import.meta.url), "..", "..", "clawpify");
111
+ const refPath = join(baseDir, "references", name.endsWith(".md") ? name : `${name}.md`);
112
+ return readFile(refPath, "utf-8");
113
+ }
114
+ async function listSkillReferences(customDir) {
115
+ const baseDir = customDir ?? join(fileURLToPath(import.meta.url), "..", "..", "clawpify");
116
+ const refDir = join(baseDir, "references");
117
+ const entries = await readdir(refDir);
118
+ return entries.filter((e) => e.endsWith(".md")).map((e) => e.replace(".md", ""));
119
+ }
120
+ async function collectMarkdown(dir, parts) {
121
+ let entries;
122
+ try {
123
+ entries = await readdir(dir, { withFileTypes: true });
124
+ } catch {
125
+ return;
126
+ }
127
+ for (const entry of entries) {
128
+ const fullPath = join(dir, entry.name);
129
+ if (entry.isDirectory()) {
130
+ await collectMarkdown(fullPath, parts);
131
+ } else if (entry.name.endsWith(".md")) {
132
+ const content = await readFile(fullPath, "utf-8");
133
+ parts.push(content);
134
+ }
135
+ }
136
+ }
137
+
90
138
  // src/agent.ts
91
139
  import Anthropic from "@anthropic-ai/sdk";
92
140
  var DEFAULT_SYSTEM_INSTRUCTION = "You're Clawpify. You help run a Shopify store. The merchant texts you to get stuff done";
@@ -108,6 +156,20 @@ var SHOPIFY_GRAPHQL_TOOL = {
108
156
  required: ["query"]
109
157
  }
110
158
  };
159
+ var LOAD_SKILL_REFERENCE_TOOL = {
160
+ name: "load_skill_reference",
161
+ description: "Load a Shopify GraphQL reference document for a specific domain. Available: products, orders, customers, inventory, discounts, collections, fulfillments, refunds, draft-orders, gift-cards, webhooks, locations, marketing, markets, menus, metafields, pages, blogs, files, shipping, shop, subscriptions, translations, segments, bulk-operations. Use this BEFORE writing GraphQL queries to get the correct syntax.",
162
+ input_schema: {
163
+ type: "object",
164
+ properties: {
165
+ reference: {
166
+ type: "string",
167
+ description: "Name of the reference to load (e.g. 'orders', 'products', 'inventory')"
168
+ }
169
+ },
170
+ required: ["reference"]
171
+ }
172
+ };
111
173
  var DEFAULT_PRICING = {
112
174
  inputPerMillion: 3,
113
175
  outputPerMillion: 15,
@@ -187,8 +249,8 @@ class ShopifyAgent {
187
249
  }
188
250
  registerPlugin(plugin) {
189
251
  const name = plugin.tool.name;
190
- if (name === "shopify_graphql") {
191
- throw new Error(`Cannot register plugin with reserved tool name "shopify_graphql"`);
252
+ if (name === "shopify_graphql" || name === "load_skill_reference") {
253
+ throw new Error(`Cannot register plugin with reserved tool name "${name}"`);
192
254
  }
193
255
  if (this.plugins.has(name)) {
194
256
  throw new Error(`Plugin with tool name "${name}" is already registered`);
@@ -208,6 +270,7 @@ class ShopifyAgent {
208
270
  buildTools() {
209
271
  const allTools = [
210
272
  SHOPIFY_GRAPHQL_TOOL,
273
+ LOAD_SKILL_REFERENCE_TOOL,
211
274
  ...[...this.plugins.values()].map((p) => p.tool)
212
275
  ];
213
276
  if (allTools.length > 0) {
@@ -245,6 +308,17 @@ class ShopifyAgent {
245
308
  return { content: content2, isError: true };
246
309
  }
247
310
  }
311
+ if (name === "load_skill_reference") {
312
+ try {
313
+ const content2 = await loadSkillReference(input.reference);
314
+ await safeHook(this.hooks.onToolResult, name, content2, false);
315
+ return { content: content2, isError: false };
316
+ } catch (error) {
317
+ const content2 = `Error: ${error instanceof Error ? error.message : String(error)}`;
318
+ await safeHook(this.hooks.onToolResult, name, content2, true);
319
+ return { content: content2, isError: true };
320
+ }
321
+ }
248
322
  if (this.plugins.has(name)) {
249
323
  const plugin = this.plugins.get(name);
250
324
  try {
@@ -488,40 +562,11 @@ class InMemoryStore {
488
562
  this.store.delete(sessionId);
489
563
  }
490
564
  }
491
-
492
- // src/skills.ts
493
- import { readdir, readFile } from "node:fs/promises";
494
- import { join } from "node:path";
495
- import { fileURLToPath } from "node:url";
496
- async function loadSkills(customDir) {
497
- const baseDir = customDir ?? join(fileURLToPath(import.meta.url), "..", "..", "clawpify");
498
- const skillParts = [];
499
- await collectMarkdown(baseDir, skillParts);
500
- return skillParts.join(`
501
-
502
- ---
503
-
504
- `);
505
- }
506
- async function collectMarkdown(dir, parts) {
507
- let entries;
508
- try {
509
- entries = await readdir(dir, { withFileTypes: true });
510
- } catch {
511
- return;
512
- }
513
- for (const entry of entries) {
514
- const fullPath = join(dir, entry.name);
515
- if (entry.isDirectory()) {
516
- await collectMarkdown(fullPath, parts);
517
- } else if (entry.name.endsWith(".md")) {
518
- const content = await readFile(fullPath, "utf-8");
519
- parts.push(content);
520
- }
521
- }
522
- }
523
565
  export {
524
566
  loadSkills,
567
+ loadSkillReference,
568
+ loadSkillMetadata,
569
+ listSkillReferences,
525
570
  getAccessToken,
526
571
  createShopifyClient,
527
572
  createAuthenticatedConfig,
package/dist/skills.d.ts CHANGED
@@ -3,6 +3,23 @@
3
3
  * Works both locally and when installed as an npm package.
4
4
  *
5
5
  * Optionally provide a custom directory path to load skills from.
6
+ *
7
+ * @deprecated Use `loadSkillMetadata()` for the system prompt and
8
+ * `loadSkillReference(name)` to load individual references on demand.
6
9
  */
7
10
  export declare function loadSkills(customDir?: string): Promise<string>;
11
+ /**
12
+ * Load only the SKILL.md metadata file (Level 1+2).
13
+ * Use this for the system prompt instead of `loadSkills()` to keep context small.
14
+ */
15
+ export declare function loadSkillMetadata(customDir?: string): Promise<string>;
16
+ /**
17
+ * Load a specific reference file on demand (Level 3).
18
+ * Returns the content of `clawpify/references/{name}.md`.
19
+ */
20
+ export declare function loadSkillReference(name: string, customDir?: string): Promise<string>;
21
+ /**
22
+ * List available reference file names (without the `.md` extension).
23
+ */
24
+ export declare function listSkillReferences(customDir?: string): Promise<string[]>;
8
25
  //# sourceMappingURL=skills.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"skills.d.ts","sourceRoot":"","sources":["../src/skills.ts"],"names":[],"mappings":"AAIA;;;;;GAKG;AACH,wBAAsB,UAAU,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CASpE"}
1
+ {"version":3,"file":"skills.d.ts","sourceRoot":"","sources":["../src/skills.ts"],"names":[],"mappings":"AAIA;;;;;;;;GAQG;AACH,wBAAsB,UAAU,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CASpE;AAED;;;GAGG;AACH,wBAAsB,iBAAiB,CACrC,SAAS,CAAC,EAAE,MAAM,GACjB,OAAO,CAAC,MAAM,CAAC,CAMjB;AAED;;;GAGG;AACH,wBAAsB,kBAAkB,CACtC,IAAI,EAAE,MAAM,EACZ,SAAS,CAAC,EAAE,MAAM,GACjB,OAAO,CAAC,MAAM,CAAC,CAUjB;AAED;;GAEG;AACH,wBAAsB,mBAAmB,CACvC,SAAS,CAAC,EAAE,MAAM,GACjB,OAAO,CAAC,MAAM,EAAE,CAAC,CAOnB"}
package/dist/skills.js CHANGED
@@ -12,6 +12,22 @@ async function loadSkills(customDir) {
12
12
 
13
13
  `);
14
14
  }
15
+ async function loadSkillMetadata(customDir) {
16
+ const baseDir = customDir ?? join(fileURLToPath(import.meta.url), "..", "..", "clawpify");
17
+ const skillPath = join(baseDir, "SKILL.md");
18
+ return readFile(skillPath, "utf-8");
19
+ }
20
+ async function loadSkillReference(name, customDir) {
21
+ const baseDir = customDir ?? join(fileURLToPath(import.meta.url), "..", "..", "clawpify");
22
+ const refPath = join(baseDir, "references", name.endsWith(".md") ? name : `${name}.md`);
23
+ return readFile(refPath, "utf-8");
24
+ }
25
+ async function listSkillReferences(customDir) {
26
+ const baseDir = customDir ?? join(fileURLToPath(import.meta.url), "..", "..", "clawpify");
27
+ const refDir = join(baseDir, "references");
28
+ const entries = await readdir(refDir);
29
+ return entries.filter((e) => e.endsWith(".md")).map((e) => e.replace(".md", ""));
30
+ }
15
31
  async function collectMarkdown(dir, parts) {
16
32
  let entries;
17
33
  try {
@@ -30,5 +46,8 @@ async function collectMarkdown(dir, parts) {
30
46
  }
31
47
  }
32
48
  export {
33
- loadSkills
49
+ loadSkills,
50
+ loadSkillReference,
51
+ loadSkillMetadata,
52
+ listSkillReferences
34
53
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@clawpify/skills",
3
- "version": "1.0.5",
3
+ "version": "1.0.6",
4
4
  "description": "Shopify Agent SDK — query and manage Shopify stores via GraphQL Admin API with AI agents and MCP",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
package/src/agent.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import Anthropic from "@anthropic-ai/sdk";
2
2
  import { ShopifyClient } from "./shopify";
3
3
  import type { MemoryStore } from "./memory";
4
+ import { loadSkillReference } from "./skills";
4
5
 
5
6
  // ---------------------------------------------------------------------------
6
7
  // Types
@@ -148,6 +149,23 @@ const SHOPIFY_GRAPHQL_TOOL: Anthropic.Tool = {
148
149
  },
149
150
  };
150
151
 
152
+ const LOAD_SKILL_REFERENCE_TOOL: Anthropic.Tool = {
153
+ name: "load_skill_reference",
154
+ description:
155
+ "Load a Shopify GraphQL reference document for a specific domain. Available: products, orders, customers, inventory, discounts, collections, fulfillments, refunds, draft-orders, gift-cards, webhooks, locations, marketing, markets, menus, metafields, pages, blogs, files, shipping, shop, subscriptions, translations, segments, bulk-operations. Use this BEFORE writing GraphQL queries to get the correct syntax.",
156
+ input_schema: {
157
+ type: "object" as const,
158
+ properties: {
159
+ reference: {
160
+ type: "string",
161
+ description:
162
+ "Name of the reference to load (e.g. 'orders', 'products', 'inventory')",
163
+ },
164
+ },
165
+ required: ["reference"],
166
+ },
167
+ };
168
+
151
169
  /** Default pricing for claude-sonnet-4-5 (USD per million tokens). */
152
170
  const DEFAULT_PRICING: ModelPricing = {
153
171
  inputPerMillion: 3,
@@ -266,9 +284,9 @@ export class ShopifyAgent {
266
284
  /** Register a plugin at runtime. Throws if a tool with the same name already exists. */
267
285
  registerPlugin(plugin: AgentPlugin): void {
268
286
  const name = plugin.tool.name;
269
- if (name === "shopify_graphql") {
287
+ if (name === "shopify_graphql" || name === "load_skill_reference") {
270
288
  throw new Error(
271
- `Cannot register plugin with reserved tool name "shopify_graphql"`
289
+ `Cannot register plugin with reserved tool name "${name}"`
272
290
  );
273
291
  }
274
292
  if (this.plugins.has(name)) {
@@ -297,6 +315,7 @@ export class ShopifyAgent {
297
315
  private buildTools(): Anthropic.Tool[] {
298
316
  const allTools: Anthropic.Tool[] = [
299
317
  SHOPIFY_GRAPHQL_TOOL,
318
+ LOAD_SKILL_REFERENCE_TOOL,
300
319
  ...[...this.plugins.values()].map((p) => p.tool),
301
320
  ];
302
321
  if (allTools.length > 0) {
@@ -348,6 +367,18 @@ export class ShopifyAgent {
348
367
  }
349
368
  }
350
369
 
370
+ if (name === "load_skill_reference") {
371
+ try {
372
+ const content = await loadSkillReference(input.reference);
373
+ await safeHook(this.hooks.onToolResult, name, content, false);
374
+ return { content, isError: false };
375
+ } catch (error) {
376
+ const content = `Error: ${error instanceof Error ? error.message : String(error)}`;
377
+ await safeHook(this.hooks.onToolResult, name, content, true);
378
+ return { content, isError: true };
379
+ }
380
+ }
381
+
351
382
  if (this.plugins.has(name)) {
352
383
  const plugin = this.plugins.get(name)!;
353
384
  try {
package/src/index.ts CHANGED
@@ -63,7 +63,12 @@ export { InMemoryStore } from "./memory";
63
63
  export type { MemoryStore } from "./memory";
64
64
 
65
65
  // Skills loader
66
- export { loadSkills } from "./skills";
66
+ export {
67
+ loadSkills,
68
+ loadSkillMetadata,
69
+ loadSkillReference,
70
+ listSkillReferences,
71
+ } from "./skills";
67
72
 
68
73
  // Re-export types for convenience
69
74
  export type { ShopifyClientConfig, GraphQLResponse } from "./shopify";
package/src/skills.ts CHANGED
@@ -7,6 +7,9 @@ import { fileURLToPath } from "node:url";
7
7
  * Works both locally and when installed as an npm package.
8
8
  *
9
9
  * Optionally provide a custom directory path to load skills from.
10
+ *
11
+ * @deprecated Use `loadSkillMetadata()` for the system prompt and
12
+ * `loadSkillReference(name)` to load individual references on demand.
10
13
  */
11
14
  export async function loadSkills(customDir?: string): Promise<string> {
12
15
  const baseDir =
@@ -19,6 +22,53 @@ export async function loadSkills(customDir?: string): Promise<string> {
19
22
  return skillParts.join("\n\n---\n\n");
20
23
  }
21
24
 
25
+ /**
26
+ * Load only the SKILL.md metadata file (Level 1+2).
27
+ * Use this for the system prompt instead of `loadSkills()` to keep context small.
28
+ */
29
+ export async function loadSkillMetadata(
30
+ customDir?: string
31
+ ): Promise<string> {
32
+ const baseDir =
33
+ customDir ??
34
+ join(fileURLToPath(import.meta.url), "..", "..", "clawpify");
35
+ const skillPath = join(baseDir, "SKILL.md");
36
+ return readFile(skillPath, "utf-8");
37
+ }
38
+
39
+ /**
40
+ * Load a specific reference file on demand (Level 3).
41
+ * Returns the content of `clawpify/references/{name}.md`.
42
+ */
43
+ export async function loadSkillReference(
44
+ name: string,
45
+ customDir?: string
46
+ ): Promise<string> {
47
+ const baseDir =
48
+ customDir ??
49
+ join(fileURLToPath(import.meta.url), "..", "..", "clawpify");
50
+ const refPath = join(
51
+ baseDir,
52
+ "references",
53
+ name.endsWith(".md") ? name : `${name}.md`
54
+ );
55
+ return readFile(refPath, "utf-8");
56
+ }
57
+
58
+ /**
59
+ * List available reference file names (without the `.md` extension).
60
+ */
61
+ export async function listSkillReferences(
62
+ customDir?: string
63
+ ): Promise<string[]> {
64
+ const baseDir =
65
+ customDir ??
66
+ join(fileURLToPath(import.meta.url), "..", "..", "clawpify");
67
+ const refDir = join(baseDir, "references");
68
+ const entries = await readdir(refDir);
69
+ return entries.filter((e) => e.endsWith(".md")).map((e) => e.replace(".md", ""));
70
+ }
71
+
22
72
  async function collectMarkdown(
23
73
  dir: string,
24
74
  parts: string[]