@wix/agent-skills 1.12.0 → 1.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/README.md +4 -0
  2. package/package.json +1 -1
  3. package/skills/wix-app/references/data-collection/WIX_DATA.md +10 -0
  4. package/skills/wix-design-system/SKILL.md +3 -1
  5. package/skills/wix-headless/references/BUILD-astro.md +10 -1
  6. package/skills/wix-headless/references/shared/STYLING.md +0 -1
  7. package/skills/wix-headless/scripts/compose.mjs +19 -24
  8. package/skills/wix-headless/scripts/patch-decorative-slots.mjs +15 -9
  9. package/skills/wix-manage/SKILL.md +32 -54
  10. package/skills/wix-manage/references/ecommerce/api-recommendation-tracking.md +3 -2
  11. package/skills/wix-manage/references/ecommerce/ecom-load-context.md +144 -0
  12. package/skills/wix-manage/references/ecommerce/ecom-pricing.md +84 -0
  13. package/skills/wix-manage/references/ecommerce/ecom-shipping.md +64 -0
  14. package/skills/wix-manage/references/ecommerce/{setup-coupons.md → pricing-promotions/ecom-pricing-create-coupon.md} +20 -6
  15. package/skills/wix-manage/references/ecommerce/{setup-discount-rules.md → pricing-promotions/ecom-pricing-create-discount-rule.md} +31 -1
  16. package/skills/wix-manage/references/ecommerce/{flow-bundle-and-save.md → pricing-promotions/ecom-pricing-flow-bundle-and-save.md} +11 -52
  17. package/skills/wix-manage/references/ecommerce/{flow-seasonal-promotion.md → pricing-promotions/ecom-pricing-flow-seasonal-promotion.md} +17 -57
  18. package/skills/wix-manage/references/ecommerce/{flow-stock-mover.md → pricing-promotions/ecom-pricing-flow-stock-mover.md} +28 -70
  19. package/skills/wix-manage/references/ecommerce/{flow-upsell-boost.md → pricing-promotions/ecom-pricing-flow-upsell-boost.md} +15 -68
  20. package/skills/wix-manage/references/ecommerce/{goal-clear-inventory.md → pricing-promotions/ecom-pricing-goal-clear-inventory.md} +22 -13
  21. package/skills/wix-manage/references/ecommerce/{goal-drive-cross-sells.md → pricing-promotions/ecom-pricing-goal-drive-cross-sells.md} +26 -8
  22. package/skills/wix-manage/references/ecommerce/{goal-increase-aov.md → pricing-promotions/ecom-pricing-goal-increase-aov.md} +32 -25
  23. package/skills/wix-manage/references/ecommerce/{goal-seasonal-revenue.md → pricing-promotions/ecom-pricing-goal-seasonal-revenue.md} +21 -8
  24. package/skills/wix-manage/references/ecommerce/{troubleshoot-discount-not-applying.md → pricing-promotions/ecom-pricing-troubleshoot-not-applying.md} +1 -1
  25. package/skills/wix-manage/references/ecommerce/recommend-ecommerce-strategy.md +23 -47
  26. package/skills/wix-manage/references/ecommerce/{api-shipping.md → shipping/ecom-shipping-api.md} +4 -3
  27. package/skills/wix-manage/references/ecommerce/{flow-fix-coverage-gaps.md → shipping/ecom-shipping-fix-coverage.md} +23 -17
  28. package/skills/wix-manage/references/ecommerce/{flow-add-free-shipping.md → shipping/ecom-shipping-free-shipping.md} +23 -18
  29. package/skills/wix-manage/references/ecommerce/{flow-optimize-shipping-rates.md → shipping/ecom-shipping-optimize-rates.md} +19 -16
  30. package/skills/wix-manage/references/ecommerce/{setup-store-pickup-location.md → shipping/ecom-shipping-setup-pickup.md} +12 -10
  31. package/skills/wix-manage/references/ecommerce/{setup-shipping-rates.md → shipping/ecom-shipping-setup-rates.md} +1 -2
  32. package/skills/wix-manage/references/ecommerce/{setup-shipping-regions.md → shipping/ecom-shipping-setup-regions.md} +1 -2
  33. package/skills/wix-manage/references/sites/query-sites.md +104 -32
  34. package/skills/wix-headless/references/astro/templates/Footer.astro +0 -27
  35. package/skills/wix-headless/references/astro/templates/Navigation.astro +0 -38
  36. package/skills/wix-headless/references/astro/templates/index.astro +0 -56
  37. package/skills/wix-manage/references/ecommerce/goal-reduce-cart-abandonment.md +0 -147
  38. package/skills/wix-manage/references/ecommerce/guardrail-discount-conflicts.md +0 -118
  39. package/skills/wix-manage/references/ecommerce/guardrail-margin-protection.md +0 -88
  40. package/skills/wix-manage/references/ecommerce/guardrail-rate-pricing-sanity.md +0 -108
  41. package/skills/wix-manage/references/ecommerce/guardrail-shipping-health.md +0 -124
  42. package/skills/wix-manage/references/ecommerce/recipe-apply-shipping-recommendations.md +0 -298
  43. package/skills/wix-manage/references/ecommerce/skill-graph.md +0 -139
  44. package/skills/wix-manage/references/ecommerce/troubleshoot-checkout-delivery-dropoff.md +0 -124
package/README.md CHANGED
@@ -92,6 +92,10 @@ Run the [`release-bump`](.github/workflows/release-bump.yml) workflow from the *
92
92
 
93
93
  See [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines on adding new skills.
94
94
 
95
+ ### Eval Token Budgets
96
+
97
+ Eval scenarios under `yaml/wix-manage-evals/` may define a top-level `maxTokens` value. The GitHub Actions eval gate compares that budget against the PR run's total tokens for the scenario and fails the PR check when the budget is exceeded. This gate-owned field is separate from `llm_judge.maxTokens`, which only configures the judge assertion.
98
+
95
99
  ## License
96
100
 
97
101
  MIT
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wix/agent-skills",
3
- "version": "1.12.0",
3
+ "version": "1.14.0",
4
4
  "description": "Wix Skills for AI coding agents — versioned npm distribution of the wix/skills content.",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -261,6 +261,16 @@ const bulkResult = await items.bulkInsert("MyCollection", [
261
261
  | `get`, `query`, `count`, `distinct` | `SCOPE.DC-DATA.READ` |
262
262
  | `insert`, `update`, `save`, `remove`, `bulkInsert`, `bulkUpdate`, `bulkRemove` | `SCOPE.DC-DATA.WRITE` |
263
263
 
264
+ ### Elevating permissions (backend only)
265
+
266
+ In backend code (service plugins, events, backend APIs), wrap the `items` method with `auth.elevate` from `@wix/essentials` to run with elevated permissions:
267
+
268
+ ```typescript
269
+ import { auth } from '@wix/essentials';
270
+ const elevatedQuery = auth.elevate(items.query);
271
+ const configResult = await elevatedQuery('MyCollection').find();
272
+ ```
273
+
264
274
  ## Date/Time Handling
265
275
 
266
276
  - **Date (date-only)**: Store as a string in "YYYY-MM-DD" format (as returned by `<input type="date" />`).
@@ -1,6 +1,8 @@
1
1
  ---
2
2
  name: wix-design-system
3
- description: Wix Design System component reference. Use when building UI with @wix/design-system, choosing components, checking props and examples, or writing tests with component testkits. Triggers on "what component", "how do I make", "WDS", "show me props", "testkit", "driver", or component names like Button, Card, Box, Text.
3
+ description: Wix Design System component reference. Use when building UI with @wix/design-system, choosing components, checking props and examples, or writing tests with component testkits. Triggers on "what component", "how do I make", "WDS", "show me props", "testkit", "driver", or component names like Button, Card, Modal, Box, Text.
4
+ metadata:
5
+ verified: true
4
6
  ---
5
7
 
6
8
  # WDS Documentation Navigator
@@ -51,13 +51,22 @@ The whole Setup window is a single message of sibling `Bash` calls — **emit th
51
51
  "navLinks": [ { "href": "/", "label": "Home" }, ... ],
52
52
  "loadedPacks": ["stores", "cms", ...],
53
53
  "packsWithComponents": ["stores", "ecom", ...],
54
- "disabledPacks": ["gift-cards", ...]
54
+ "disabledPacks": ["gift-cards", ...],
55
+ "navPath": ".wix/nav.astro",
56
+ "footerPath": ".wix/footer.astro",
57
+ "homePath": ".wix/home.astro"
55
58
  }
56
59
  COMPOSE
57
60
  ```
58
61
 
59
62
  The compose-input shape is documented in `scripts/compose.mjs`'s header.
60
63
 
64
+ **The entire visible page is LLM-generated.** `compose.mjs` still writes the plumbing — `global.css`, `astro.config.mjs`, and `Layout.astro` (the `<html>`/`<head>` shell that imports the fonts, `global.css`, ClientRouter, and the `<Navigation/>`+`<Footer/>` components) — but the **header, footer, and home page are authored by an LLM**, not from templates (there are no `Navigation.astro` / `Footer.astro` / `index.astro` templates anymore). Between `emit-design-tokens.mjs` and `compose.mjs`, dispatch a **Default-tier** generator that reads the token vocabulary at `.wix/design-tokens.css` and authors three files, then pass their paths:
65
+ - `.wix/nav.astro` → `Navigation.astro` (site header). Contract: one `<header class="site-nav" transition:persist="site-nav">` with brand mark + real nav links (`/`, `/about`, `/faq`), a `<!-- nav:links -->` + `<!-- nav:actions -->` marker and an empty `<div class="nav-actions">` for later vertical patches, and a no-JS mobile toggle.
66
+ - `.wix/footer.astro` → `Footer.astro`. Contract: one `<footer class="site-footer">` with brand, a short tagline, and the nav links.
67
+ - `.wix/home.astro` → `index.astro` (full home page). Contract: frontmatter importing `Layout` + a `<Layout>…</Layout>` wrapper; one `<!-- home:<pack> -->` marker per loaded home-contributing pack; and **two decorative-image slots** — `hero` + one section (e.g. `about`). **Each slot is a DEDICATED, EMPTY placeholder element that holds no copy** — e.g. `<div class="hero-image" data-decorative-slot="hero" style="aspect-ratio:4/5"></div>` sitting *beside* the hero text, NOT the `data-decorative-slot` attribute slapped on the content-bearing `<section>`. The image patcher injects an `<img>` only into an empty slot element; if the slot wraps real copy it is skipped (the image never lands). Any element type works (`<div>`/`<figure>`/…) as long as it is its own empty element.
68
+ - **All three:** compose tokens as utility classes so they match the theme; write real copy (no `{{…}}`); keep `transition:persist` + the `site-nav`/`site-footer` classes (the View-Transitions + `global.css` styling target them). `compose.mjs` writes each verbatim and **errors if any path is missing** (`NO_NAV`/`NO_FOOTER`/`NO_HOME`). Manifest records `nav`/`footer`/`home` = `"llm-generated"`.
69
+
61
70
  **In the SAME message — the business Setup Step 4 batch** (frontend-blind; `SETUP.md` owns recipes/package set). These overlap the bridge's `compose.mjs` (~20 s) so it adds no serial wall:
62
71
 
63
72
  3. `Bash` × N — app installs, one curl per `pack.apps[*]` → `SETUP.md` § Step 4a. Packs with no `apps[*]` (`cms`, `ecom`, `gift-cards`) install nothing — skip them.
@@ -46,7 +46,6 @@ These are layout/spacing/typography concerns that should always be utilities, ne
46
46
  > **Never reintroduce a named `--spacing-*` scale.** In Tailwind v4 the `--spacing-*` namespace also generates the width/sizing families (`max-w-*`, `w-*`, `min-w-*`, …), so any `--spacing-<key>` token shadows the matching `max-w-<key>`. The current fix works because the skill's spacing steps happen to equal Tailwind's numeric defaults — but if a brand ever needs genuinely *custom* spacing **values**, put them under a different namespace (e.g. `--rhythm-*`) or use arbitrary values (`py-[5.5rem]`); do not revive `--spacing-*`.
47
47
 
48
48
  **Width / reading columns:** `max-w-md`, `max-w-3xl`, `max-w-6xl`, `max-w-prose` now resolve correctly to the `--container-*` keys (no spacing collision), so use them freely; `container-reading` (the designer `@utility`) or an arbitrary `max-w-[48rem]` also work.
49
-
50
49
  If a designer's `global.css` contains rules like `.featured-section { padding-block: 6rem; }` or `.product-card-body { display: flex; flex-direction: column; gap: 0.5rem; }`, those are misplaced — they belong in markup as utilities (`py-24`, `flex flex-col gap-2`). Inventing such classes ships broken layouts: every consumer needs the designer to have pre-declared the class, and Tailwind v4 silently drops the references when the rule is missing.
51
50
 
52
51
  ## Required tokens — the component-CSS template contract
@@ -212,6 +212,14 @@ const loadedPacks = Array.isArray(input.loadedPacks) ? input.loadedPacks : [];
212
212
  const packsWithComponents = Array.isArray(input.packsWithComponents) ? input.packsWithComponents : [];
213
213
  const disabledPacks = Array.isArray(input.disabledPacks) ? input.disabledPacks : [];
214
214
 
215
+ // Full-page LLM generation (this branch): the LLM authors the entire visible
216
+ // page — header (Navigation.astro), footer (Footer.astro), and home page
217
+ // (index.astro). compose writes each verbatim; there are no templates for them.
218
+ const resolveIn = (p) => { const s = typeof p === "string" ? p.trim() : ""; return s ? (isAbsolute(s) ? s : join(projectDir, s)) : null; };
219
+ const navPath = resolveIn(input.navPath);
220
+ const footerPath = resolveIn(input.footerPath);
221
+ const homePath = resolveIn(input.homePath);
222
+
215
223
  const brandName = brand.name ?? "Brand";
216
224
 
217
225
  // ── small color helper (derivation fail-safe only) ────────────────────────────
@@ -454,27 +462,16 @@ const navItems = navLinks
454
462
  .filter((l) => l && l.href != null && l.label != null)
455
463
  .map((l) => ({ href: String(l.href), label: String(l.label) }));
456
464
 
457
- // ── 4. Navigation.astro ──────────────────────────────────────────────────────────
465
+ // ── 4. Navigation.astro (LLM-generated, verbatim) ─────────────────────────────
458
466
  {
459
- let out = stripAstroHeader(readTemplate("Navigation.astro"));
460
- out = out.replaceAll("{{shell.navBrandMark}}", shell.navBrandMark ?? brandName);
461
- const links = navItems
462
- .map((l) => ` <li class="site-nav-item"><a href="${escAttr(l.href)}">${l.label}</a></li>`)
463
- .join("\n");
464
- out = out.replace(/^\s*\{\{nav\.links\}\}\s*$/m, links);
465
- writeProject("src/components/Navigation.astro", out);
467
+ if (!navPath || !existsSync(navPath)) die("NO_NAV", `LLM-generated header required via navPath (none at ${navPath ?? "<unset>"})`);
468
+ writeProject("src/components/Navigation.astro", readFileSync(navPath, "utf8"));
466
469
  }
467
470
 
468
- // ── 5. Footer.astro ──────────────────────────────────────────────────────────────
471
+ // ── 5. Footer.astro (LLM-generated, verbatim) ─────────────────────────────────
469
472
  {
470
- let out = stripAstroHeader(readTemplate("Footer.astro"));
471
- out = out.replaceAll("{{brand.name}}", brandName);
472
- out = out.replaceAll("{{shell.footerTagline}}", shell.footerTagline ?? "");
473
- const links = navItems
474
- .map((l) => ` <li><a href="${escAttr(l.href)}">${l.label}</a></li>`)
475
- .join("\n");
476
- out = out.replace(/^\s*\{\{nav\.links\}\}\s*$/m, links);
477
- writeProject("src/components/Footer.astro", out);
473
+ if (!footerPath || !existsSync(footerPath)) die("NO_FOOTER", `LLM-generated footer required via footerPath (none at ${footerPath ?? "<unset>"})`);
474
+ writeProject("src/components/Footer.astro", readFileSync(footerPath, "utf8"));
478
475
  }
479
476
 
480
477
  // ── 6. index.astro ────────────────────────────────────────────────────────────────
@@ -485,13 +482,8 @@ const HOME_CONTRIBUTING = ["stores", "bookings", "gift-cards"]; // canonical ord
485
482
  const homePool = new Set([...loadedPacks, ...disabledPacks]);
486
483
  const homeMarkerPacks = HOME_CONTRIBUTING.filter((p) => homePool.has(p));
487
484
  {
488
- let out = stripAstroHeader(readTemplate("index.astro"));
489
- out = out.replaceAll("{{shell.heroHeadline}}", shell.heroHeadline ?? brandName);
490
- out = out.replaceAll("{{shell.heroSub}}", shell.heroSub ?? "");
491
- out = out.replaceAll("{{brand.name}}", brandName);
492
- const markers = homeMarkerPacks.map((p) => ` <!-- home:${p} -->`).join("\n");
493
- out = out.replace(/^\s*\{\{home-markers\}\}\s*$/m, markers);
494
- writeProject("src/pages/index.astro", out);
485
+ if (!homePath || !existsSync(homePath)) die("NO_HOME", `LLM-generated home page required via homePath (none at ${homePath ?? "<unset>"})`);
486
+ writeProject("src/pages/index.astro", readFileSync(homePath, "utf8"));
495
487
  }
496
488
 
497
489
  // ── manifest (the orchestrator parses this off stdout) ────────────────────────
@@ -508,6 +500,9 @@ const manifest = {
508
500
  phase: "compose",
509
501
  data: {
510
502
  filesWritten,
503
+ nav: "llm-generated",
504
+ footer: "llm-generated",
505
+ home: "llm-generated",
511
506
  componentCssImports: packsWithComponents,
512
507
  homeMarkers: homeMarkerPacks.map((p) => `home:${p}`),
513
508
  tokensApplied: {
@@ -2,10 +2,11 @@
2
2
  // Inject Image-Phase-1 decorative URLs into the page shells.
3
3
  //
4
4
  // The design-system Composer (index.astro) and the Phase 4 page designers write
5
- // `<div data-decorative-slot="<key>">…</div>` placeholders in src/pages/*.astro. Image Phase 1 returns a slot→URL map
6
- // in its JSON return; the orchestrator pipes that map (as JSON) into this
5
+ // `<el data-decorative-slot="<key>">…</el>` placeholders in src/pages/*.astro
6
+ // (any element — <div>, <section>, <figure>…). Image Phase 1 returns a slot→URL
7
+ // map in its JSON return; the orchestrator pipes that map (as JSON) into this
7
8
  // script's stdin. This script reads the map + walks src/pages/*.astro,
8
- // then injects an <img> as the first child of each matching slot div —
9
+ // then injects an <img> as the first child of each matching empty slot element —
9
10
  // pure string substitution, no LLM, no file rewrites.
10
11
  //
11
12
  // Usage:
@@ -23,9 +24,9 @@
23
24
  // blocks mode or Image Phase 1 had no URLs to publish).
24
25
  // - src/pages missing at <scaffold-dir> and in any single subdir one
25
26
  // level down → exit 2 status="error".
26
- // - For each `data-decorative-slot="<key>"` in src/pages/*.astro:
27
- // * Key has no URL in the input map → leave the div alone.
28
- // * Div already has a non-comment child → skip with a warning.
27
+ // - For each `data-decorative-slot="<key>"` element in src/pages/*.astro:
28
+ // * Key has no URL in the input map → leave the element alone.
29
+ // * Element already has a non-comment child → skip with a warning.
29
30
  // * Otherwise inject <img …> as the first child.
30
31
  // - Output JSON summary of patches/skips/warnings to stdout.
31
32
 
@@ -99,14 +100,19 @@ const patched = [];
99
100
  const skipped = [];
100
101
  const warnings = [];
101
102
 
102
- const SLOT_DIV_REGEX = /(<div[^>]*\bdata-decorative-slot="([^"]+)"[^>]*>)([\s\S]*?)(<\/div>)/g;
103
+ // Match ANY element carrying data-decorative-slot, not just <div>. Full-page
104
+ // LLM generation routinely puts the slot on a <section>/<figure>/<picture>;
105
+ // the closing tag is matched by backreference (\2) to the opening tag name.
106
+ // Slots are empty placeholders by contract, so the non-greedy body cannot
107
+ // straddle a sibling element of the same tag.
108
+ const SLOT_REGEX = /(<([a-zA-Z][\w-]*)[^>]*\bdata-decorative-slot="([^"]+)"[^>]*>)([\s\S]*?)(<\/\2>)/g;
103
109
 
104
110
  for (const file of candidates) {
105
111
  const original = readFileSync(file, "utf8");
106
112
  let modified = original;
107
113
  let fileChanged = false;
108
114
 
109
- modified = modified.replace(SLOT_DIV_REGEX, (match, openTag, slotKey, inner, closeTag) => {
115
+ modified = modified.replace(SLOT_REGEX, (match, openTag, _tagName, slotKey, inner, closeTag) => {
110
116
  const url = urlMap[slotKey];
111
117
  if (!url) {
112
118
  skipped.push({ file, slot: slotKey, reason: "no URL for this slot in input map" });
@@ -121,7 +127,7 @@ for (const file of candidates) {
121
127
  }
122
128
 
123
129
  if (stripped.length > 0) {
124
- warnings.push({ file, slot: slotKey, reason: "div has existing non-image child content; not patching to avoid clobber" });
130
+ warnings.push({ file, slot: slotKey, reason: "slot element has existing non-image child content; not patching to avoid clobber" });
125
131
  return match;
126
132
  }
127
133
 
@@ -121,66 +121,44 @@ These recipes do NOT cover frontend development or SDK usage for displaying data
121
121
  ## eCommerce
122
122
 
123
123
  **Routing — pick the right entry point:**
124
- - **Any sales/business improvement request** (boost sales, promotions, help my business, holiday deals, improve revenue, discounts, shipping, coupons, clearance) → use [Recommend: eCommerce Strategy](references/ecommerce/recommend-ecommerce-strategy.md). This is the **default entry point** — it analyzes ALL domains (discounts, shipping, future: gift cards, taxes) and generates cross-domain recommendations. Do NOT ask clarifying questions.
125
- - **Apply previously generated shipping recommendations** → use [Recipe: Apply Shipping Recommendations](references/ecommerce/recipe-apply-shipping-recommendations.md)
126
- - **Store pickup configuration** → use [Setup Store Pickup Location](references/ecommerce/setup-store-pickup-location.md)
127
- - **Discount not working at checkout** → use [Troubleshoot: Discount Not Applying](references/ecommerce/troubleshoot-discount-not-applying.md)
128
- - **Checkout delivery step drop-off** → use [Troubleshoot: Checkout Delivery Drop-off](references/ecommerce/troubleshoot-checkout-delivery-dropoff.md)
124
+ - **Any sales/business improvement request** (boost sales, promotions, help my business, holiday deals, improve revenue, discounts, shipping, coupons, clearance) → use [Recommend: eCommerce Strategy](references/ecommerce/recommend-ecommerce-strategy.md). This is the **default entry point** — it analyzes ALL domains (discounts, shipping) and generates cross-domain recommendations. Do NOT ask clarifying questions.
125
+ - **Pricing & promotions** (coupons, discount rules, ribbons, sales) → use the [Pricing & Promotions](references/ecommerce/ecom-pricing.md) dispatcher.
126
+ - **Shipping setup** (rates, regions, pickup, free shipping, fix coverage) → use the [Shipping](references/ecommerce/ecom-shipping.md) dispatcher.
129
127
 
130
- ### [Recommend: eCommerce Strategy](references/ecommerce/recommend-ecommerce-strategy.md)
131
- **THE entry point for all eCommerce recommendation requests.** Unified skill that analyzes site data across ALL domains (discounts + shipping), generates up to 5 cross-domain recommendations, and persists them to the tracking database. Covers discount strategies (seasonal, upsell, stock mover, bundling) AND shipping optimization (coverage gaps, free shipping, rate strategy, carrier backup). Use this for ANY business improvement request.
132
-
133
- ### [Recipe: Apply Shipping Recommendations](references/ecommerce/recipe-apply-shipping-recommendations.md)
134
- **Technical:** Applies AI-generated shipping recommendations. Creates or updates shipping options based on recommendation data.
128
+ ### [eCommerce: Load Context](references/ecommerce/ecom-load-context.md)
129
+ **L1 loader** — loads general site data (siteId, country, currency, industry, catalog analytics) needed by every eCommerce category. Each category dispatcher loads this before tag-matching; runs once per session.
135
130
 
136
- ### [Setup Store Pickup Location](references/ecommerce/setup-store-pickup-location.md)
137
- **Technical:** Configures in-store pickup at checkout using Delivery Profiles API.
131
+ ### [Recommend: eCommerce Strategy](references/ecommerce/recommend-ecommerce-strategy.md)
132
+ **Entry point for all eCommerce recommendation requests.** Unified skill that analyzes site data across ALL domains (discounts + shipping), generates up to 5 cross-domain recommendations, and persists them to the tracking database. Covers discount strategies (seasonal, upsell, stock mover, bundling) AND shipping optimization (coverage gaps, free shipping, rate strategy, carrier backup). Use this for ANY business improvement request.
138
133
 
139
- ### [Troubleshoot: Discount Not Applying](references/ecommerce/troubleshoot-discount-not-applying.md)
140
- **Technical:** Diagnostic tree for inactive discounts — checks active status, time window, scope targeting, revision mismatch, app installation.
134
+ ### [Pricing & Promotions](references/ecommerce/ecom-pricing.md)
135
+ **Dispatcher** — routes coupon/discount/sale/ribbon/bundle requests to the right leaf recipe (create coupon, create discount rule, troubleshoot discount-not-applying), and routes strategic "run a sale / boost sales" requests to `recommend-ecommerce-strategy`.
141
136
 
142
- ### [Troubleshoot: Checkout Delivery Drop-off](references/ecommerce/troubleshoot-checkout-delivery-dropoff.md)
143
- **Technical:** Diagnostic tree for delivery step conversion below 65% benchmark.
137
+ ### [Shipping](references/ecommerce/ecom-shipping.md)
138
+ **Dispatcher** — routes shipping-setup requests (rates, regions, pickup, free shipping, fix coverage, optimize rates) to the right leaf recipe. The Shipping Options + Delivery Profiles APIs have no public docs page; `ecom-shipping-api.md` is the authoritative inline reference.
144
139
 
145
140
  <details>
146
- <summary>Internal skills (loaded automatically by the entry points above — do NOT use directly)</summary>
147
-
148
- #### Goals
149
- - [Goal: Increase AOV](references/ecommerce/goal-increase-aov.md) — UPSELL_BOOST
150
- - [Goal: Clear Inventory](references/ecommerce/goal-clear-inventory.md) — STOCK_MOVER
151
- - [Goal: Seasonal Revenue](references/ecommerce/goal-seasonal-revenue.md) — SEASONAL
152
- - [Goal: Drive Cross-Sells](references/ecommerce/goal-drive-cross-sells.md) — BUNDLE_AND_SAVE
153
- - [Goal: Reduce Cart Abandonment](references/ecommerce/goal-reduce-cart-abandonment.md) — Shipping
154
-
155
- #### Flows
156
- - [Flow: Upsell Boost](references/ecommerce/flow-upsell-boost.md)
157
- - [Flow: Bundle and Save](references/ecommerce/flow-bundle-and-save.md)
158
- - [Flow: Stock Mover](references/ecommerce/flow-stock-mover.md)
159
- - [Flow: Seasonal Promotion](references/ecommerce/flow-seasonal-promotion.md)
160
- - [Flow: Fix Coverage Gaps](references/ecommerce/flow-fix-coverage-gaps.md)
161
- - [Flow: Add Free Shipping](references/ecommerce/flow-add-free-shipping.md)
162
- - [Flow: Optimize Shipping Rates](references/ecommerce/flow-optimize-shipping-rates.md)
163
-
164
- #### Guardrails
165
- - [Guardrail: Discount Conflicts](references/ecommerce/guardrail-discount-conflicts.md)
166
- - [Guardrail: Margin Protection](references/ecommerce/guardrail-margin-protection.md)
167
- - [Guardrail: Shipping Health](references/ecommerce/guardrail-shipping-health.md)
168
- - [Guardrail: Rate Pricing Sanity](references/ecommerce/guardrail-rate-pricing-sanity.md)
169
-
170
- #### Config & API References
171
- - [API: Recommendation Tracking](references/ecommerce/api-recommendation-tracking.md)
172
- - [API: Shipping Delivery](references/ecommerce/api-shipping.md)
173
- - [Setup: Discount Rules](references/ecommerce/setup-discount-rules.md)
174
- - [Setup: Coupons](references/ecommerce/setup-coupons.md)
175
- - [Setup: Shipping Regions](references/ecommerce/setup-shipping-regions.md)
176
- - [Setup: Shipping Rates](references/ecommerce/setup-shipping-rates.md)
177
-
178
- #### Tracking
179
- - Tracking is built into [Recommend: eCommerce Strategy](references/ecommerce/recommend-ecommerce-strategy.md) (Steps 2 + 8) — no separate skill needed
180
- - [API: Recommendation Tracking](references/ecommerce/api-recommendation-tracking.md) — CRUD API reference for the tracking service
181
-
182
- #### Reference
183
- - [Skill Graph](references/ecommerce/skill-graph.md)
141
+ <summary>Internal skills (loaded automatically by the dispatchers / orchestrator above — do NOT use directly)</summary>
142
+
143
+ #### Pricing & promotions leaves (loaded by the Pricing dispatcher or by the strategy orchestrator)
144
+ - [Pricing: Create Coupon](references/ecommerce/pricing-promotions/ecom-pricing-create-coupon.md)
145
+ - [Pricing: Create Discount Rule](references/ecommerce/pricing-promotions/ecom-pricing-create-discount-rule.md)
146
+ - [Pricing: Discount Not Applying](references/ecommerce/pricing-promotions/ecom-pricing-troubleshoot-not-applying.md)
147
+ - Goals: [Increase AOV](references/ecommerce/pricing-promotions/ecom-pricing-goal-increase-aov.md), [Clear Inventory](references/ecommerce/pricing-promotions/ecom-pricing-goal-clear-inventory.md), [Seasonal Revenue](references/ecommerce/pricing-promotions/ecom-pricing-goal-seasonal-revenue.md), [Drive Cross-Sells](references/ecommerce/pricing-promotions/ecom-pricing-goal-drive-cross-sells.md)
148
+ - Flows: [Upsell Boost](references/ecommerce/pricing-promotions/ecom-pricing-flow-upsell-boost.md), [Bundle and Save](references/ecommerce/pricing-promotions/ecom-pricing-flow-bundle-and-save.md), [Stock Mover](references/ecommerce/pricing-promotions/ecom-pricing-flow-stock-mover.md), [Seasonal Promotion](references/ecommerce/pricing-promotions/ecom-pricing-flow-seasonal-promotion.md)
149
+
150
+ #### Shipping leaves (loaded by the Shipping dispatcher)
151
+ - [Set Up Rates](references/ecommerce/shipping/ecom-shipping-setup-rates.md)
152
+ - [Set Up Regions](references/ecommerce/shipping/ecom-shipping-setup-regions.md)
153
+ - [Set Up Pickup / Local Delivery](references/ecommerce/shipping/ecom-shipping-setup-pickup.md)
154
+ - [Add Free Shipping](references/ecommerce/shipping/ecom-shipping-free-shipping.md)
155
+ - [Optimize Rates](references/ecommerce/shipping/ecom-shipping-optimize-rates.md)
156
+ - [Fix Coverage Gaps](references/ecommerce/shipping/ecom-shipping-fix-coverage.md)
157
+ - [API Reference](references/ecommerce/shipping/ecom-shipping-api.md) — inline spec for Shipping Options + Delivery Profiles
158
+
159
+ #### Cross-cutting tracking
160
+ - [API: Recommendation Tracking](references/ecommerce/api-recommendation-tracking.md) — load BEFORE generating any recommendation; persists PROPOSED state and tracks MarkExecuting → MarkDone/MarkFailed.
161
+
184
162
 
185
163
  </details>
186
164
 
@@ -1,7 +1,6 @@
1
1
  ---
2
2
  name: "API: Recommendation Tracking"
3
- description: CRUD API for persisting and managing the lifecycle of AI-generated recommendations. Tracks state transitions from PROPOSED through APPROVED, EXECUTING, to DONE/FAILED/REJECTED. Every recommendation must be persisted here before presenting to the merchant.
4
- layer: config
3
+ description: Cross-cutting tracking API for AI-generated recommendations across eCommerce categories (checkout, shipping, pricing). ALWAYS LOAD BEFORE generating a "give me N recommendations / concrete actions" response, in addition to the category recipe.
5
4
  ---
6
5
  # API: Recommendation Tracking Service
7
6
 
@@ -11,6 +10,8 @@ This service persists recommendations in a database and tracks their lifecycle s
11
10
 
12
11
  **Base URL**: `https://manage.wix.com/_api/agentic-recommendations/v1/agentic-recommendations`
13
12
 
13
+ > **Internal-but-callable API.** This is a Wix-internal service with NO public `dev.wix.com` docs page. It **IS callable via `CallWixSiteAPI`** in the authenticated editor/dashboard context the MCP runs in (verified: the endpoints return auth/validation errors, not 404). This file is the authoritative spec — do not try to `ReadFullDocsArticle` an external doc for it.
14
+
14
15
  ## How to call these APIs
15
16
 
16
17
  Use `CallWixSiteAPI` to invoke each endpoint:
@@ -0,0 +1,144 @@
1
+ ---
2
+ name: "eCommerce: Load Context"
3
+ description: "eCommerce L1 context loader — calls wix-profile-client/v4/profile/metasite (NOT site-properties) to load siteId, country, currency, industry, last-30-day visitors/orders/GPV. Skip if already loaded."
4
+ ---
5
+
6
+ # eCommerce: Load Context
7
+
8
+ > **L1 loader pattern.** Each L1 domain (eCommerce, Stores, Get-paid, Contacts, …) owns its own context loader. This file is the **eCommerce** L1 loader. Other L1s have their own (e.g. `stores-load-context.md` will detect Catalog V1/V3 for Stores categories). The boilerplate (Step 1 + 2) is small; the **field list and runtime detections differ by L1**.
9
+
10
+ > **When to run.** Called from the dispatch block of any eCommerce category's `default.md` (Tax, Pricing & promotions, …) before tag-matching. Run **once per session**. If `siteData.country` is already in your conversation context, skip the API calls below and return immediately — every subsequent eCommerce category entry reuses the loaded data.
11
+
12
+ This is the canonical extract of Steps 1 + 3 from today's `recommend-ecommerce-strategy.md`, scoped to the fields eCommerce categories actually need.
13
+
14
+ ## Step 1 — Resolve siteId
15
+
16
+ If a `siteId` is not already known, call `ListWixSites`:
17
+
18
+ ```
19
+ ListWixSites()
20
+ ```
21
+
22
+ - If the merchant referenced a site by name, match it.
23
+ - If exactly one site exists, auto-select it.
24
+ - Otherwise, ask the merchant which site to use.
25
+
26
+ **Do not proceed without a `siteId`.**
27
+
28
+ ## Step 2 — Load business profile (the canonical endpoint)
29
+
30
+ Same call today's `recommend-ecommerce-strategy.md` Step 3 makes. The field list below is the **eCommerce** subset — orchestrator-needed metrics (visitors / orders / GPV → AOV) plus locale/currency/industry used for dispatch tags and recommendations.
31
+
32
+ ```
33
+ CallWixSiteAPI(
34
+ url: "https://www.wix.com/wix-profile-client/v4/profile/metasite",
35
+ method: "POST",
36
+ body: {
37
+ "fields": [
38
+ "language",
39
+ "merchant_business_country",
40
+ "suggested_main_industry",
41
+ "suggested_sub_industry",
42
+ "last_30_days_distinct_visitors",
43
+ "last_30_days_orders_count",
44
+ "online_gpv_last_30_days",
45
+ "payment_currency"
46
+ ]
47
+ }
48
+ )
49
+ ```
50
+
51
+ Extract each field into conversation context as `siteData`:
52
+
53
+ | Field in response | Maps to | Notes |
54
+ |---|---|---|
55
+ | `fields.language.aSingleValue.aString` | `siteData.language` | Locale code (e.g. `en-US`) |
56
+ | `fields.merchant_business_country.aSingleValue.aString` | `siteData.country` | ISO-3166-1 alpha-2 |
57
+ | `fields.suggested_main_industry.aSingleValue.aString` | `siteData.industry` | Used by Pricing orchestrator's goal classification |
58
+ | `fields.suggested_sub_industry.aSingleValue.aString` | `siteData.subIndustry` | Optional |
59
+ | `fields.last_30_days_distinct_visitors.aSingleValue.aLong` | `siteData.visitors30d` | **Returned as JSON string** — `parseInt` before arithmetic |
60
+ | `fields.last_30_days_orders_count.aSingleValue.aLong` | `siteData.orders30d` | parseInt |
61
+ | `fields.online_gpv_last_30_days.aSingleValue.aLong` | `siteData.gpv30d` | parseInt |
62
+ | `fields.payment_currency.aSingleValue.aString` | `siteData.currency` | ISO-4217 |
63
+
64
+ Missing fields ⇒ no data for that field (don't fabricate). If `merchant_business_country`, `suggested_main_industry`, or `online_gpv_last_30_days` are missing or null, surface to the merchant: "Cannot resolve required site data: <fields>." and stop.
65
+
66
+ **Derived value:** `siteData.aov = parseInt(gpv30d) / parseInt(orders30d)` — in `siteData.currency` units.
67
+
68
+ ## Step 2b — Detect catalog presence and load analytics
69
+
70
+ Call `GetCatalogAnalytics` once here so all downstream pricing/promotions flows can reference `siteData.catalogAnalytics` without re-fetching.
71
+
72
+ ```
73
+ CallWixSiteAPI(
74
+ url: "https://manage.wix.com/recommendations/v1/recommendations/get-catalog-analytics-tool",
75
+ method: "POST",
76
+ body: {
77
+ "aggregates": [
78
+ {"op":"count","field":"price"},
79
+ {"op":"min","field":"price"},
80
+ {"op":"max","field":"price"},
81
+ {"op":"avg","field":"profitMargin"},
82
+ {"op":"quantiles","field":"price","q":[0.5,0.75,0.9]},
83
+ {"op":"sum","field":"quantity"},
84
+ {"op":"sum","field":"ordersCount"}
85
+ ],
86
+ "minMarginPct": 0.15
87
+ }
88
+ )
89
+ ```
90
+
91
+ Save the full `categoryGroups` array as `siteData.catalogAnalytics`. From the "All Products" group extract:
92
+ - `siteData.catalogProductCount` = `count()` value (0 if missing or call fails)
93
+ - `siteData.hasCatalog` = `siteData.catalogProductCount > 0`
94
+
95
+ If the call fails, set `siteData.hasCatalog = true` (assume catalog exists; let downstream fail naturally).
96
+
97
+ **This data is used by all pricing & promotions discount flows.** Flows that require a product catalog (Bundle & Save, Upsell Boost, Stock Mover, Seasonal) MUST check `siteData.hasCatalog` before proceeding — if `false`, stop with: "This site has no products. Set up your product catalog first before running promotions."
98
+
99
+ ## Step 3 — Derive region (used by dispatch context tags)
100
+
101
+ From `siteData.country`, set `siteData.region`:
102
+ - `BR | AR | MX | CL | CO | PE` → `LATAM`
103
+ - EU member states (`DE | FR | IT | ES | NL | BE | PL | SE | IE | AT | PT | FI | DK | CZ | HU | GR | RO | BG | HR | SK | SI | LT | LV | EE | CY | MT | LU`) → `EU`
104
+ - `JP | CN | KR | SG | AU | NZ | IN | TH | ID | MY | PH | VN | HK | TW` → `APAC`
105
+ - otherwise → `null`
106
+
107
+ (UK is **not** in `region:EU`. AU/NZ are in `region:APAC` but Tax inclusive-pricing rules differ — handled inside Tax promotions.)
108
+
109
+ ## Step 4 — Return
110
+
111
+ Return immediately. Subsequent eCommerce category dispatches read `siteData.*` from conversation context without re-fetching. If the agent crosses into a different L1 (e.g. Stores) within the same session, that L1's loader will see `siteData.country` already loaded, skip its Steps 1-3, and only fire its own general derivations.
112
+
113
+ ## Architectural rule — general site data only
114
+
115
+ **This file must contain only general / cross-cutting site data** — fields that **every** category in this L1 needs. It must **not** include L3-category-specific runtime detection (e.g. Tax calculator, Catalog V1/V3, payment-provider state, shipping-coverage state).
116
+
117
+ Reasoning:
118
+ - Per-category detect calls accumulate cost on every session entry, even when the agent never visits that category.
119
+ - L3-specific state can use APIs that aren't TPA-public (e.g. the Wix Tax FQDNs are `exposure: INTERNAL`); if the L1 loader depends on them, the entire L1 fails to load. Keeping the loader general-only contains the blast radius.
120
+ - Per-category state can change independently of the merchant; loading it eagerly invites stale-data bugs.
121
+
122
+ **Where category-specific runtime data is detected instead:** inside the category's `default.md` (Step before dispatch) or inside the specific promotion that needs it. The L1 loader does **not** prime per-category fields; the category does its own detection lazily, only when its own intent dispatch fires.
123
+
124
+ Concretely for the categories we know about:
125
+ - **Tax** — calculator detection (Manual vs Avalara) belongs in `ecom-tax.md` (the merged category-doc + dispatcher) or in each Tax promotion when it runs. Not here.
126
+ - **Catalog V1/V3 version detection** — belongs in the Stores category loader when Stores migrates. `getCatalogAnalytics` (product count/margin/price) is already loaded here as a cross-cutting concern; V1/V3 detection is a separate, Stores-specific signal.
127
+ - **Payments & finance** (when Get-paid migrates) — payment-provider state belongs in `finance-and-payments/get-paid-finance-default.md`.
128
+
129
+ ## What this file does NOT do
130
+
131
+ - **Does not detect per-category runtime state** (see architectural rule above).
132
+ - **Does not load tracking history.** But: if any recipe in this session generates a recommendation to present to the merchant — regardless of which eCommerce category — it MUST load [API: Recommendation Tracking](https://dev.wix.com/docs/api-reference/business-solutions/e-commerce/skills/api-recommendation-tracking) and follow the lifecycle: load history before generating (Query), persist as PROPOSED via BatchCreate before presenting, and track execution via MarkExecuting / MarkDone / MarkFailed. This obligation applies to ALL eCommerce domains.
133
+ - **Does not load non-eCommerce L1 fields** (catalog V1/V3 version detection, payment provider, …). Those belong inside the owning L1's category-level files (per the architectural rule). Note: `getCatalogAnalytics` (product count, margin, price distribution) IS loaded here as a cross-cutting concern; Catalog V1/V3 version detection is separate and belongs in the Stores category's own loader.
134
+ - **Does not enforce dispatch.** The category's `default.md` is what scores tags and picks a promotion — this file only fills general site context.
135
+
136
+ ## Pattern for future L1 loaders
137
+
138
+ When a new L1 domain is migrated to the routing tree, author a `<l1>-load-context.md` at its root:
139
+
140
+ - `references/stores/stores-load-context.md` — Stores L1 loader. Steps 1-3 same boilerplate, Step 4 runtime-detects Catalog version (V1/V3) and any other Stores-specific fields.
141
+ - `references/get-paid/get-paid-load-context.md` — Get-paid L1 loader. Step 4 inspects payment provider state, enabled methods.
142
+ - `references/contacts/contacts-load-context.md` — Contacts L1 loader. Possibly minimal — most CRM ops don't need runtime detection.
143
+
144
+ Each lives sibling to its L1's category-docs. Each is referenced from every category's `default.md` within its L1. Skip-if-loaded check across L1s makes cross-L1 sessions cost-free.
@@ -0,0 +1,84 @@
1
+ ---
2
+ name: "Pricing & Promotions"
3
+ description: Pricing & Promotions boundary owner — discounts, coupons, sales, ribbons, bundles. **Always load this dispatcher first when a question touches both discount work and refunds, payments, product-price edits, or shipping rates** — the rules for which side owns each topic live in this file, not in this README line.
4
+ ---
5
+
6
+ # Pricing & Promotions
7
+
8
+ Discount rules, coupon codes, sales, ribbons, bundles, tiered pricing, and the strategic side of "run a promotion to grow revenue".
9
+
10
+ > **Routing rule (READ FIRST).** Any merchant query that mentions BOTH a Pricing-side topic (discount, coupon, sale, ribbon, bundle, promotion strategy) AND a NON-pricing-side topic (refunding a past order, processing a payment, editing the product's base price, shipping rates) MUST be answered by loading this dispatcher first AND the relevant other category (refunds → Get Paid / Dashboard; price → Catalog; shipping rates → Shipping). Do NOT route mixed queries from the WixREADME index alone; the binding decision lives here.
11
+
12
+ **Pricing & promotions is NOT:**
13
+ - The product price itself or its description/image → see **Catalog** (those are product fields).
14
+ - A standing $0 shipping option/region rate → see **Shipping & fulfillment**.
15
+ - Refunding a previous discounted order → route to verified Get Paid/payment docs or Dashboard guidance.
16
+
17
+ > **Before dispatching** — confirm MerchantContext is loaded. If `siteData.country` is not in your conversation context, load it via [Load Merchant Context](https://dev.wix.com/docs/api-reference/business-solutions/e-commerce/skills/e-commerce-load-context). Skip if already loaded.
18
+ >
19
+ > **Promotion dispatch.** Score each entry below by (a) the merchant's query → `intent:*` tags, (b) MerchantContext → context tags. Load the **highest-scoring** entry. Ties → highest `priority`. No match → follow the base recipe at the bottom.
20
+ >
21
+ > **Do not fall back to legacy `setup-*` or `flow-*` pricing slugs.** The skills below replaced earlier `…/skills/setup-coupons` and `…/skills/flow-<name>` articles during the routing-tree migration. If a slug below returns a transient 404 (rawdocs ingestion delay), **retry the same URL after a brief pause** — do NOT load any `setup-coupons` or `flow-*` legacy version even if it appears in the WixREADME index; that content is stale pre-migration material that contradicts this dispatcher.
22
+
23
+ ### Actions — concrete operations
24
+
25
+ > - [Create coupon](https://dev.wix.com/docs/api-reference/business-solutions/e-commerce/skills/pricing-create-coupon) — tags: `[intent:create-coupon]` · priority 0
26
+ > - [Create discount rule (auto-apply)](https://dev.wix.com/docs/api-reference/business-solutions/e-commerce/skills/pricing-create-discount-rule) — tags: `[intent:create-discount-rule]` · priority 0
27
+ > - [Add sale ribbon / new ribbon](https://dev.wix.com/docs/api-reference/business-solutions/e-commerce/skills/pricing-create-discount-rule) — tags: `[intent:add-ribbon]` · priority 0 · *ribbons are configured via Discount Rules; same recipe*
28
+ > - [Schedule a future sale](https://dev.wix.com/docs/api-reference/business-solutions/e-commerce/skills/pricing-create-discount-rule) — tags: `[intent:schedule-sale]` · priority 0 · *uses Discount Rules with `startTime` in the future*
29
+
30
+ ### Business flows — the orchestrator
31
+
32
+ The single business-flow orchestrator (`recommend-ecommerce-strategy`) handles all strategic discount intents. It classifies internally (SEASONAL / UPSELL_BOOST / STOCK_MOVER / BUNDLE_AND_SAVE / ABANDONED_CART) and loads its `goal-*` / `flow-*` support files from the kept ecommerce-root siblings.
33
+
34
+ > - [Run a sale / promotion strategy](https://dev.wix.com/docs/api-reference/business-solutions/e-commerce/skills/recommend-e-commerce-strategy) — tags: `[intent:run-a-sale]` · priority 0
35
+ > - [Boost my business / increase sales](https://dev.wix.com/docs/api-reference/business-solutions/e-commerce/skills/recommend-e-commerce-strategy) — tags: `[intent:boost-business]` · priority 0
36
+ > - [Seasonal / holiday promotion](https://dev.wix.com/docs/api-reference/business-solutions/e-commerce/skills/recommend-e-commerce-strategy) — tags: `[intent:seasonal-promo]` · priority 0
37
+ > - [Clearance / move slow stock](https://dev.wix.com/docs/api-reference/business-solutions/e-commerce/skills/recommend-e-commerce-strategy) — tags: `[intent:clearance]` · priority 0
38
+ > - [Increase AOV (bundle / upsell)](https://dev.wix.com/docs/api-reference/business-solutions/e-commerce/skills/recommend-e-commerce-strategy) — tags: `[intent:increase-aov]` · priority 0
39
+ >
40
+ > **If the orchestrator above returns a 404** — do not stop. Classify the merchant intent directly and load the matching goal skill via `ReadFullDocsArticle`, then follow its routing chain into the flow skill:
41
+ > - Holiday / event / date mentioned (SEASONAL — takes priority over all other signals) → [Goal: Seasonal Revenue](https://dev.wix.com/docs/api-reference/business-solutions/e-commerce/skills/goal-seasonal-revenue)
42
+ > - "Boost sales", "increase AOV", "upsell", "spend more" (UPSELL_BOOST) → [Goal: Increase AOV](https://dev.wix.com/docs/api-reference/business-solutions/e-commerce/skills/goal-increase-aov)
43
+ > - "Clearance", "slow stock", "overstock", "move inventory" (STOCK_MOVER) → [Goal: Clear Inventory](https://dev.wix.com/docs/api-reference/business-solutions/e-commerce/skills/goal-clear-inventory)
44
+ > - "Bundle", "cross-sell", "buy together", "more items per order" (BUNDLE_AND_SAVE) → [Goal: Drive Cross-Sells](https://dev.wix.com/docs/api-reference/business-solutions/e-commerce/skills/goal-drive-cross-sells)
45
+
46
+ ### Info / troubleshoot / recommendation
47
+
48
+ > - [Discount not applying — diagnose](https://dev.wix.com/docs/api-reference/business-solutions/e-commerce/skills/pricing-discount-not-applying) — tags: `[intent:troubleshoot]` · priority 0
49
+ > - [View active discounts (Coupons API)](https://dev.wix.com/docs/api-reference/business-solutions/coupons/coupons/query-coupons) — tags: `[intent:view-active-discounts]` · priority 0 · **API doc, no skill** (per §7.5)
50
+ > - [View active discounts (Discount Rules API)](https://dev.wix.com/docs/api-reference/business-solutions/e-commerce/discount-rules/query-discount-rules) — tags: `[intent:view-active-rules]` · priority 0 · **API doc, no skill**
51
+ > - [Coupon usage stats](https://dev.wix.com/docs/api-reference/business-solutions/coupons/coupons/get-coupon-usage) — tags: `[intent:coupon-usage-stats]` · priority 0 · **API doc, no skill**
52
+ > - Competitive pricing check (how do my prices compare?) — tags: `[intent:competitive-pricing]` · *no Wix API for competitor data — advise the merchant to benchmark externally (Google Shopping / market research); Wix only exposes their own catalog prices via Catalog API*
53
+
54
+ ### Cross-category routes (handled in another category)
55
+
56
+ > - [Change product price](https://dev.wix.com/docs/api-reference/business-solutions/stores/products-v3/update-product) — tags: `[intent:change-price]` · *price is a product field — Catalog API*
57
+ > - [Set compare-at price](https://dev.wix.com/docs/api-reference/business-solutions/stores/products-v3/update-product) — tags: `[intent:set-compare-at]` · *Catalog*
58
+ > - [Free shipping over $X (promo rule)](https://dev.wix.com/docs/api-reference/business-solutions/e-commerce/skills/pricing-create-discount-rule) — tags: `[intent:free-shipping-promo]` · *belongs here as a promo rule; a $0 shipping rate is Shipping*
59
+
60
+ ## Tag matching
61
+
62
+ The agent matches the merchant's natural-language query to an `intent:*` tag (cues are in each promotion file's `description`), AND matches MerchantContext to any context tags. A promotion's tags must ALL be satisfied for it to be eligible. Among eligible promotions, the one with the highest tag-count wins; ties broken by `priority`.
63
+
64
+ ### Worked examples
65
+
66
+ | Merchant query | MerchantContext | Match |
67
+ |---|---|---|
68
+ | "Create a 20% off coupon" | any | `ecom-pricing-create-coupon` via `[intent:create-coupon]` |
69
+ | "Run a Black Friday sale" | any | `recommend-ecommerce-strategy` via `[intent:run-a-sale]` (orchestrator classifies as SEASONAL internally) |
70
+ | "Help me boost my sales" | any | `recommend-ecommerce-strategy` via `[intent:boost-business]` |
71
+ | "My coupon code XMAS isn't working" | any | `ecom-pricing-troubleshoot-not-applying` |
72
+ | "Show me my active discounts" | any | `query-coupons` API doc (no skill — per §7.5) |
73
+ | "Change the price of product Y" | any | Catalog cross-route (re-dispatch to Catalog when that category exists) |
74
+
75
+ ## Base recipe (fallback)
76
+
77
+ If nothing matches, the merchant query is too vague. Ask **one** clarifying question:
78
+
79
+ > "Do you want to (a) **create** a specific discount/coupon now, (b) **strategize** a sale or promotion campaign, or (c) **fix** a discount that isn't applying?"
80
+
81
+ Map the answer → re-dispatch:
82
+ - (a) → `ecom-pricing-create-coupon` (default for "create a discount")
83
+ - (b) → `recommend-ecommerce-strategy`
84
+ - (c) → `ecom-pricing-troubleshoot-not-applying`