Update to Brainerce
Snapshot Oct 24, 2026 · 18:05 UTC · version 2.0.4
Collection source: downloaded plugin package. These snapshots do not have a confirmed matching collection source. Differences in file lists alone do not establish changes to the package.
Instructions updated for brainerce-product-onboarding
Full description — Now says: list this item, put this in the shop, set up my new range, copy an existing product, or fix the stock count on something. Also covers duplicating a product,...
Observed in instructions or declared skills. Runtime behavior has not been tested.
Up to 10 plugins free · no card required.
All fields and original values.
Full description
Sep 30, 2026 · 23:07 UTC
I have something new to sell, list this item, put this in the shop, set up my new range, copy an existing product, or fix the stock count on something. Also covers duplicating a near-identical product and correcting inventory after a sto...
Oct 24, 2026 · 18:05 UTC
list this item, put this in the shop, set up my new range, copy an existing product, or fix the stock count on something. Also covers duplicating a product, publishing the whole catalog to a storefront, stock corrections and stock histor...
Skill instructions
Sep 30, 2026 · 23:07 UTC
"Add a product to a Brainerce store properly, from creating it through to category, tags, stock and publishing. Use when the merchant says add a product, I have something new to sell, list this item, put this in the shop, set up my new r...
Oct 24, 2026 · 18:05 UTC
'Add a product to a Brainerce store properly, from creating it through to category, tags, stock and publishing. Use when the merchant says add a product, list this item, put this in the shop, set up my new range, copy an existing product...
Compare saved observations
Download comparison JSONSKILL.md text changes
− removed · + added
--- before +++ after @@ -1,13 +1,15 @@ --- name: brainerce-product-onboarding -description: "Add a product to a Brainerce store properly, from creating it through to category, tags, stock and publishing. Use when the merchant says add a product, I have something new to sell, list this item, put this in the shop, set up my new range, copy an existing product, or fix the stock count on something. Also covers duplicating a near-identical product and correcting inventory after a stock take. For store owners, not developers. Do not choose this to change price or description on a product that already exists and is set up, that is a quick edit and needs no sequence. Do not choose this for reading reviews or ratings, use brainerce-analytics. Do not choose this to find products that were left as drafts, use brainerce-store-health. Do not choose this to decide variant versus custom field, use brainerce-store-architecture. Keywords: add product, new product, list an item, create product, upload product, stock count, inventory, restock, categorise, tags, publish, duplicate product, product variants." +description: 'Add a product to a Brainerce store properly, from creating it through to category, tags, stock and publishing. Use when the merchant says add a product, list this item, put this in the shop, set up my new range, copy an existing product, or fix the stock count on something. Also covers duplicating a product, publishing the whole catalog to a storefront, stock corrections and stock history. For store owners, not developers. A price or description edit on a set-up product needs no sequence. Not for reviews (brainerce-analytics), finding drafts (brainerce-store-health) or variant versus custom field (brainerce-store-architecture). Keywords: add product, new product, create product, stock count, inventory, restock, categorise, tags, publish, publish all, duplicate product, bulk import, CSV import, product images, alt text, stock history, sale price dates.' compatibility: ChatGPT, Claude Code, Claude Desktop, Cursor maintainer: Brainerce metadata: author: Brainerce - version: "1.0.0" + version: '1.0.0' --- +⛔ **Before you call anything a dashboard task, look for `search_tools` in your tool list.** Some connections carry a small curated list PLUS a way to reach everything else. Where `search_tools` exists, search for what the merchant asked for and call any hit through the `call_read_tool` / `call_write_tool` / `call_destructive_tool` it names. The dashboard is the honest answer only when your list has no `search_tools`, or the search comes back empty. A few things are refused through it deliberately (payment provider setup, refunds and recording payments, gift cards), which is why an empty result there is a real answer rather than a gap. + Get a new product from "I have this thing to sell" to a listing customers can actually find and buy. ## Core principle @@ -37,7 +39,7 @@ ### 1. Look before you create -Call `list_products` with the name the merchant gave. If something close already exists, say so and ask whether they want a new product or an edit to that one. Creating a near-duplicate is easy to do and annoying to undo, and this connector cannot delete the mistake. +Call `list_products` with the name the merchant gave. If something close already exists, say so and ask whether they want a new product or an edit to that one. Creating a near-duplicate is easy to do and annoying to undo, and on the ChatGPT app there is no delete tool to clean it up with. If the merchant wants something very like an existing product, `duplicate_product` is faster and less error prone than retyping everything. Duplicate first, then edit the differences with `update_product`. @@ -47,27 +49,82 @@ - **Name** and **price**, always. Read the currency from `get_store`; do not assume. - **Description**: offer to draft one, but show it to the merchant before it goes live. This is their voice, on their storefront. -- **Images**: if the merchant has image URLs, pass them; the platform downloads and stores the images rather than linking to someone else's server. +- **A photo the merchant attached to the chat**: on the ChatGPT app there is no route for it. The receiving field was withdrawn on 2026-09-23 after the submission portal refused the tool scan over its metadata, so do not promise it and do not invent a `download_url`. Ask for a direct image FILE URL instead and pass it in `images`. On the full connector the attachment route still exists. +- **Images by URL**: on the full connector the fast route is `ingest_media_asset({ sourceUrl })` first, then pass what it returns as `{ url, key }`. That image is on the Brainerce CDN and shows up straight away. A bare external URL also works everywhere, but it is only **queued** for download and stays hidden from the storefront, the cart and the checkout until it lands. The URL has to point at an actual image file (`.jpg`, `.png`, `.webp`); a link to a page that merely displays a photo, like a stock-photo listing, downloads as HTML and is dropped. + ⛔ The response echoes an `importStatus` per image. `pending` means queued and **not yet live**, so report it as queued, never as done. A failure that happens later will not be in that response either; re-read the product with `get_product` to see it. +- **Stock, at creation time**: for a SIMPLE product `create_product` takes `inventory: { total }` inline. Set it here. ⛔ For a product with variants that product-level field is ignored: each entry in `variants` carries its own `inventory` (a plain number), so put the opening count on every variant, or you get a product whose every size reads 0. See step 5. - **Variants**: sizes, colours, materials. Ask if the product obviously has them ("a t-shirt" almost certainly does) and do not silently create a single-variant product for something that needs five. +- ⛔ **Downloads are a separate two-step, and not on the ChatGPT app.** `create_product` and `update_product` silently drop the download fields rather than refusing, so passing `isDownloadable` gives you a product that looks created and sells nothing. Never rely on it. On the full connector (Claude, or an API key) create the product first as an ordinary item, then `search_tools "digital download file"` and call `ingest_download_file({ sourceUrl })` with a public direct link to the file, then `set_product_download_files({ productId, fileKeys })` with the `fileKey` it returned. The second call is destructive, so the host asks the merchant to approve it. Tell the merchant the limits before you start: 50MB per file, no plain text or CSV (zip it), a simple product only (variable products and kits take files per variant in the dashboard), nothing is scanned for malware, and attaching does not touch stock tracking, so read `result.note` and relay it if the product still cannot be bought. On the ChatGPT app none of this exists: say it is a dashboard job before you call any tool. + +### 3 and 4. Category and tags, in the same call + +**Do this inline on `create_product` rather than as four separate calls.** It takes three fields: + +- `categoryNames`: category names to put it in. Matched case-insensitively against what already exists, and created if nothing matches. +- `brandNames`: same behaviour for the brand. +- `tags`: tag names. Same again, resolved or created case-insensitively. + +So "a ceramic mug in Kitchen, tagged handmade and gift" is one call with `categoryNames: ["Kitchen"]` and `tags: ["handmade", "gift"]`, not a list, a create, a list and a create. Case-insensitive matching is what stops "Summer" landing next to "summer". + +If you already hold real category ids, `categories` and `brands` take ids instead, and unknown ids are rejected rather than created. -### 3. Put it somewhere customers will find it +**The category page itself.** `update_category` writes the page copy a storefront shows: `description` (long-form HTML) and `metaDescription` (the page's meta description, 50 to 160 characters), and it can pin the Google product taxonomy id with `googleTaxonomyId` (a number pins it; `null` clears the pin and it is worked out from the name again). Each takes `null` to clear. For a category with no copy, `list_seo_category_gaps` lists them worst first, and `generate_seo_category_description` writes and saves one from the products in it. -Call `list_categories`, then place the product in a real category. If nothing fits, `create_category` makes one, but check the list first; stores accumulate near-duplicate categories fast. +⛔ **`list_categories`, `create_category`, `list_tags` and `create_tag` are OAuth-only.** A merchant connected with a `brainerce_` API key gets "This tool requires OAuth authentication and is not available via API key" from every one of them. That is not a store problem and it is not worth retrying. The inline `categoryNames` / `tags` fields above go through `create_product` and work on either connection, which is the other reason they are the default route here. -### 4. Tag it +### 5. Set stock, and mind which kind of product it is -Call `list_tags` before `create_tag`. Reuse an existing tag over creating "Summer" next to "summer" and "Summer 2026". Tags are how the merchant will filter and how sales get targeted later. +A product with no stock is not buyable, and a merchant who thinks they have listed something for sale will not check. If the merchant has not said how many, ask; do not default to a number. -### 5. Set stock +- **Simple product**: `set_product_stock` sets the absolute total. It also accepts `product` as a name or slug instead of `productId`, and it refuses rather than guessing if the name matches more than one product. +- **Product with variants**: ⛔ **`set_product_stock` is for SIMPLE products only.** Called on a variant product it does not refuse and it does not warn. It writes a product-level stock row, but a variant product's stock is reported as the **sum of its variants** and that row is never read back, so the number you set simply never becomes the answer. You get a success and no change the merchant can see. Set the opening stock per variant in `variants[].inventory` on `create_product` at step 2, or change one afterwards with `set_variant_stock`. +- **Changing one variant's stock afterwards** is `set_variant_stock`: `variantId` comes from `get_product`, `newTotal` is the absolute count. It is on the ChatGPT app's curated list (since 2026-09-15) as well as the full connector. If it is somehow not in your tool list, say plainly that per-variant stock is a dashboard job, under the product's variant editor, and do not reach for `set_product_stock` as a substitute: on a variant product that call succeeds and changes nothing the merchant can see. +- **Kit** (`type: 'KIT'`, a gift box or set assembled from other products): ⛔ **a kit has no stock of its own and there is no number to set.** `set_product_stock` on a kit is **refused** with an explanation rather than half-working. How many kits can be sold is worked out from the contents (the component that runs out first decides), so the way to make a kit sellable is to stock its components, not the kit. `get_kit_components` reports that figure as `available`; `get_product_inventory` will not answer for a kit, because there is no row to read. -Call `set_product_stock`. A product with no stock is not buyable, and a merchant who thinks they have listed something for sale will not check. If the merchant has not said how many, ask; do not default to a number. + ⛔ **`create_product` with `type: 'KIT'` creates an EMPTY kit, and an empty kit cannot be bought.** The create succeeds and the product looks normal, but until it has contents it has no price and a shopper's add-to-cart is refused. Follow it with **`set_kit_components`** in the same breath, or you have handed the merchant a dead product. ⛔ That tool **REPLACES** the whole list rather than appending, so when you are editing an existing kit, read it with `get_kit_components` first and send back every component it should end up with. A `VARIABLE` component needs its `componentVariantId` pinned; a kit cannot contain another kit. -`get_product_inventory` reads back what is actually there, and is the tool for a stock take correction as well. + `set_kit_components` is **not on the ChatGPT app's curated list**. If it is not in your tool list, do not present a created kit as finished: say plainly that the kit still needs its contents and that adding them is a dashboard job (open the kit, then its contents list) or an admin-API one (`PUT /v1/products/{id}/kit-components`, SDK `setKitComponents`). + + `kitPricingMode` **is** settable here, on `create_product` and `update_product`, alongside `kitDiscountValue`. `FIXED` (the default) charges the `basePrice` you set and it stays put. `SUM` makes the kit cost exactly what its contents cost, recomputed on every read, so a component going on sale lowers the kit price on its own. `SUM_MINUS_PERCENT` is that sum less `kitDiscountValue` percent (0-100). ⛔ On the two SUM modes the `basePrice` you passed is a **placeholder that is never charged** — say so, or the merchant will think the number they gave you is the price. + +`get_product_inventory` reads back what is actually there, and is the tool for a stock take correction as well. For a variant product its `inventory` total is already summed across the variants. ### 6. Offer to publish, do not assume Products can exist as drafts. Tell the merchant which state it is in and ask before making it visible. "Do you want this live on the storefront now, or held as a draft while you add photos?" is one sentence and prevents both of the bad outcomes. +**Visible on the storefront needs two things, and creating gives you at most one.** The product's `status` must be `active` (the default; a `draft` never shows), **and** the product must be published to the sales channel the storefront reads from. `create_product` does not publish. ⛔ **Its `platforms` field is not a publish path either**: it expects a channel record id with a literal `vc:` prefix, so a `vc_` connection id or a channel name matches nothing, the call still reports success, and the product stays invisible. `update_product` has no `platforms` field at all. The publish route is `publish_product_to_channel`, which takes the channel's `vc_` id, its id from `list_sales_channels`, or its exact name, and it is on the ChatGPT app's curated list as well as the full connector. It is OAuth-only: on a `brainerce_` API-key connection it refuses, and publishing is then a dashboard step (Products → the product → sales channels). Call it once per product after creating, or ask which channel when the store has more than one. A merchant who says "I added it but the shop is empty" is almost always missing this step, and `list_products` with `salesChannelId` shows what is actually live. + +**Many products at once.** Publish a catalog: `bulk_update_platforms({ filter: { status: 'active' }, vcPublishTo: [channel] })`; `vcPublishTo` accepts the channel id, its `vc_` id or its name. `filter: { status: 'active' }` is the "all my products" form (an empty filter is refused), `productIds` scopes it to a list, `vcUnpublishFrom` is the reverse, and it changes visibility only. A large catalog is queued and the result carries `{ queued: true, jobId }`: report it as in progress and poll `get_bulk_job_status`, do not call it again. It is on the ChatGPT app's curated list since 2026-09-15, and unlike the single publish it also works on a `brainerce_` API key with `products:write`, so on an API-key connection it is the publish route. `set_product_channel_app_visibility` (full connector) hides one product from a connector app such as Google Merchant Center without unpublishing it from the storefront, which is a different thing. + +## The media library + +Images live in a reusable library rather than only on the product, and merchants ask about it as "my photos" or "the images I already uploaded". On the full connector: + +- `ingest_media_asset` pulls an external URL onto the Brainerce CDN and hands back the `{ url, key }` to attach. This is the route that makes an image show up immediately. +- `list_media_assets` and `list_media_assets_advanced` browse what is already uploaded, `get_media_asset` reads one, and `get_media_asset_usage` says which products are using it, which is the check to run before removing anything. +- `set_media_asset_alt` writes alt text, which is what the SEO score on the products table is asking for. +- `list_media_folders`, `create_media_folder` and `move_media_assets` organise them. + +None of these are on the ChatGPT app's curated list. Check your tool list before offering any of it, and point at the dashboard's Media section otherwise. ⛔ And the attached-photo route is NOT a way around that on the ChatGPT app: a merchant who drops a photo into the conversation still needs to give you a direct image URL, or upload it in the dashboard. + +## Stock beyond the count + +Four inventory tools arrived on the full connector on 2026-09-15; none of them are on the ChatGPT app. + +- `get_inventory_history` is the movement ledger for one product or variant: every change with its delta, the balance before and after, who made it and the order behind it. It is the answer to "why does this say 3 when I counted 10". +- `get_stock_velocity` is units per day over 7, 30 or 90 days, fastest first. Only products that sold at least one unit appear, so a product missing from it sold nothing, which is not the same as being out of stock. +- `upsert_channel_inventory_policy` reserves part of the shared stock pool for one sales channel; it does not add or remove stock. `trigger_inventory_sync` pushes the current count out to connected platforms in the background. The policy is per product or variant and per channel: `protectedQuantity` units that no other channel may sell, 0 removes it, and it is refused when the item is not tracked or the figure exceeds what is left after the other channels' reservations. `list_channel_inventory_policies` shows the split and `delete_channel_inventory_policy` clears one. A completed order from a channel takes its units off that channel's own `protectedQuantity` first, so the figure shrinks as the channel sells and the other channels' shares stay whole; cancelled or refunded units go back to the shared pool, not to the share. Every cart, checkout and order refuses a line that does not fit in what the channel may sell, and `getProduct` / `getProducts` / `getInventory` on a channel show that number, not the whole pool. The sync is one-way and outbound (Shopify, WooCommerce and the like), overwrites the count they hold, and is refused when no installed connector can receive inventory; it is not a stock change and not a pull. + +Warehouses, suppliers and purchase orders have no tool on any connection and stay in the dashboard under Inventory. + +## Two product fields worth knowing + +Both are on `create_product` and `update_product` on every connection since 2026-09-15: + +- **A sale-price window.** `salePriceStartsAt` and `salePriceEndsAt` (ISO 8601) schedule a sale price. Set both or neither; a lone bound is ignored. This is a product-level sale, which is the right tool for "this item is on offer this month"; a store-wide or category-wide sale is a discount rule, in `brainerce-launch-a-sale`. One variant can carry its own window (same two fields, same rules, overrides the product's) on `create_variant`, `update_variant` and `bulk_save_variants`; `null` clears a bound, and in `bulk_save_variants` an omitted bound keeps the stored one. The window is enforced everywhere: the storefront, cart and checkout use the regular price before the start and after the end, and the same dates reach the Google and Meta feeds, so the merchant does NOT need to clear the sale price when the sale is over. A variant with a sale price but no dates of its own follows the product's dates. +- **Shipping weight and dimensions.** `shippingWeightValue` with `shippingWeightUnit`, and `shippingLengthValue`, `shippingWidthValue`, `shippingHeightValue` with `shippingDimensionUnit`. Weight-based shipping rates and carrier label quotes read these, so a product without a weight ships at the rate's base cost and cannot be quoted at a carrier. Ask for them when the store charges by weight. + ## Response shape > ✓ Ceramic Mug is created at 65 ILS, in Kitchen, tagged handmade and gift, with 40 in stock. @@ -86,14 +143,16 @@ ## Rules -- Never say "added to your store" for a draft. Say it is a draft and what that means. -- Check `list_products` before creating, and `list_tags` and `list_categories` before creating those. Duplicates cannot be deleted from here. +- Never say "added to your store" for a draft. Say it is a draft and what that means. Never say "on your storefront" for a product you have not published to the channel with `publish_product_to_channel`. +- **When the merchant asks what is still missing, how to start selling, or whether the shop is ready, call `get_store_setup_status` first** (on the ChatGPT connector and the full connector) and answer from its checklist, not from general e-commerce knowledge. It reports the store name, sales channel, products published to a channel, shipping, payment provider and tax, each with a `nextAction`. A payment provider in test mode counts as not done. +- Check `list_products` before creating. For categories and tags, pass `categoryNames` and `tags` on `create_product` and let the case-insensitive match do the de-duplicating; do not call `list_categories` or `list_tags` first, because they are OAuth-only and fail outright on an API-key connection. - Ask for stock rather than defaulting to zero or to some number you picked. - Show generated descriptions to the merchant before publishing. This is their shop's voice. - `create_product` reaches an external origin when it downloads images from URLs, and running it twice creates two products, not one. If a call is ambiguous about whether it went through, check with `list_products` rather than re-running it. - `update_product` replaces the fields it touches rather than merging into them. Read the current product with `get_product` before an edit so you know what you are about to overwrite. -- Several products at once: do them one at a time and report as you go. This connector has no bulk create, and a half-finished batch is worse than a slow one. -- This connector cannot delete a product. Say so if the merchant asks, and point at the Brainerce dashboard. +- Several products at once: **check your tool list for `bulk_create_products` first.** It exists on the full connector and is the right tool for a CSV, a supplier list or a migration; looping `create_product` a thousand times is the exact thing it replaces. It is queued, so it returns a `jobId` and the products appear over the following seconds or minutes: report it as **started**, not finished, then poll `get_bulk_create_products_status` with that `jobId`. Re-sending a batch is safe, because a row whose SKU or `externalId` already exists is skipped rather than duplicated. +- If `bulk_create_products` is not in your tool list, which is the case on the ChatGPT app's curated list, do them one at a time and report as you go. A half-finished batch is worse than a slow one. +- Deleting a product: `delete_product` exists on the full connector but is not on the ChatGPT app's curated list. If it is not in your tool list, say deletion is a dashboard job rather than saying the platform cannot do it. ## Cross-skill connections
Full technical diff · 2 changed fields
changed /description
"Add a product to a Brainerce store properly, from creating it through to category, tags, stock and publishing. Use when the merchant says add a product, I have something new to sell, list this item, put this in the shop, set up my new range, copy an existing product, or fix the stock count on something. Also covers duplicating a near-identical product and correcting inventory after a stock take. For store owners, not developers. Do not choose this to change price or description on a product that already exists and is set up, that is a quick edit and needs no sequence. Do not choose this for reading reviews or ratings, use brainerce-analytics. Do not choose this to find products that were left as drafts, use brainerce-store-health. Do not choose this to decide variant versus custom field, use brainerce-store-architecture. Keywords: add product, new product, list an item, create product, upload product, stock count, inventory, restock, categorise, tags, publish, duplicate product, product variants."
"Add a product to a Brainerce store properly, from creating it through to category, tags, stock and publishing. Use when the merchant says add a product, list this item, put this in the shop, set up my new range, copy an existing product, or fix the stock count on something. Also covers duplicating a product, publishing the whole catalog to a storefront, stock corrections and stock history. For store owners, not developers. A price or description edit on a set-up product needs no sequence. Not for reviews (brainerce-analytics), finding drafts (brainerce-store-health) or variant versus custom field (brainerce-store-architecture). Keywords: add product, new product, create product, stock count, inventory, restock, categorise, tags, publish, publish all, duplicate product, bulk import, CSV import, product images, alt text, stock history, sale price dates."
changed /skill_md_contents
"---\nname: brainerce-product-onboarding\ndescription: \"Add a product to a Brainerce store properly, from creating it through to category, tags, stock and publishing. Use when the merchant says add a product, I have something new to sell, list this item, put this in the shop, set up my new range, copy an existing product, or fix the stock count on something. Also covers duplicating a near-identical product and correcting inventory after a stock take. For store owners, not developers. Do not choose this to change price or description on a product that already exists and is set up, that is a quick edit and needs no sequence. Do not choose this for reading reviews or ratings, use brainerce-analytics. Do not choose this to find products that were left as drafts, use brainerce-store-health. Do not choose this to decide variant versus custom field, use brainerce-store-architecture. Keywords: add product, new product, list an item, create product, upload product, stock count, inventory, restock, categorise, tags, publish, duplicate product, product variants.\"\ncompatibility: ChatGPT, Claude Code, Claude Desktop, Cursor\nmaintainer: Brainerce\nmetadata:\n author: Brainerce\n version: \"1.0.0\"\n---\n\nGet a new product from \"I have this thing to sell\" to a listing customers can actually find and buy.\n\n## Core principle\n\nA created product is not a finished product. A merchant who is told \"done\" and then finds the item invisible on their own storefront, uncategorised, or with no stock, has been misled. Walk the whole sequence, and say which parts you skipped.\n\n## When to use this skill first\n\n- \"Add a product\", \"I have something new to sell\", \"list this\".\n- \"Set up my new range\" or several products at once.\n- \"Make another one like this\": duplicating an existing listing.\n- \"Fix the stock on X\", \"I counted 40 of these\".\n\n## When NOT to use this skill first\n\n- Changing a price or a description on an existing, fully set up product: just do it, no sequence needed.\n- \"What do people think of this product\", ratings and reviews: use `brainerce-analytics`.\n- \"Find products I left as drafts\": use `brainerce-store-health`.\n- \"Put this product on sale\": use `brainerce-launch-a-sale`.\n- \"Should size be a variant or an option\", or any question about how the catalog should be modelled before the product exists: use `brainerce-store-architecture`.\n\n---\n\n## The sequence\n\nDo these in order. Later steps depend on earlier ones, and skipping one is how products end up invisible.\n\n### 1. Look before you create\n\nCall `list_products` with the name the merchant gave. If something close already exists, say so and ask whether they want a new product or an edit to that one. Creating a near-duplicate is easy to do and annoying to undo, and this connector cannot delete the mistake.\n\nIf the merchant wants something very like an existing product, `duplicate_product` is faster and less error prone than retyping everything. Duplicate first, then edit the differences with `update_product`.\n\n### 2. Create it\n\nCall `create_product`. Ask for what is missing rather than filling it in yourself:\n\n- **Name** and **price**, always. Read the currency from `get_store`; do not assume.\n- **Description**: offer to draft one, but show it to the merchant before it goes live. This is their voice, on their storefront.\n- **Images**: if the merchant has image URLs, pass them; the platform downloads and stores the images rather than linking to someone else's server.\n- **Variants**: sizes, colours, materials. Ask if the product obviously has them (\"a t-shirt\" almost certainly does) and do not silently create a single-variant product for something that needs five.\n\n### 3. Put it somewhere customers will find it\n\nCall `list_categories`, then place the product in a real category. If nothing fits, `create_category` makes one, but check the list first; stores accumulate near-duplicate categories fast.\n\n### 4. Tag it\n\nCall `list_tags` before `create_tag`. Reuse an existing tag over creating \"Summer\" next to \"summer\" and \"Summer 2026\". Tags are how the merchant will filter and how sales get targeted later.\n\n### 5. Set stock\n\nCall `set_product_stock`. A product with no stock is not buyable, and a merchant who thinks they have listed something for sale will not check. If the merchant has not said how many, ask; do not default to a number.\n\n`get_product_inventory` reads back what is actually there, and is the tool for a stock take correction as well.\n\n### 6. Offer to publish, do not assume\n\nProducts can exist as drafts. Tell the merchant which state it is in and ask before making it visible. \"Do you want this live on the storefront now, or held as a draft while you add photos?\" is one sentence and prevents both of the bad outcomes.\n\n## Response shape\n\n> ✓ Ceramic Mug is created at 65 ILS, in Kitchen, tagged handmade and gift, with 40 in stock.\n>\n> It is currently a draft, so customers cannot see it yet.\n>\n> Want me to publish it, or would you rather add photos first?\n\n**Partly done, use this shape:**\n\n> ✓ Ceramic Mug is created at 65 ILS with 40 in stock.\n>\n> Two things I did not do: it is not in a category yet, and it has no images. Uncategorised products are hard for customers to find.\n>\n> Want me to put it in Kitchen?\n\n## Rules\n\n- Never say \"added to your store\" for a draft. Say it is a draft and what that means.\n- Check `list_products` before creating, and `list_tags` and `list_categories` before creating those. Duplicates cannot be deleted from here.\n- Ask for stock rather than defaulting to zero or to some number you picked.\n- Show generated descriptions to the merchant before publishing. This is their shop's voice.\n- `create_product` reaches an external origin when it downloads images from URLs, and running it twice creates two products, not one. If a call is ambiguous about whether it went through, check with `list_products` rather than re-running it.\n- `update_product` replaces the fields it touches rather than merging into them. Read the current product with `get_product` before an edit so you know what you are about to overwrite.\n- Several products at once: do them one at a time and report as you go. This connector has no bulk create, and a half-finished batch is worse than a slow one.\n- This connector cannot delete a product. Say so if the merchant asks, and point at the Brainerce dashboard.\n\n## Cross-skill connections\n\n- Putting the new product on sale: `brainerce-launch-a-sale`.\n- Reviews and ratings on it: `brainerce-analytics`.\n- Finding old drafts and out-of-stock items across the store: `brainerce-store-health`.\n- Deciding variant versus custom field, or category versus tag: `brainerce-store-architecture`.\n- Filling in a custom field on the new product: `brainerce-custom-fields`.\n\nRoute once, and do not bounce back and forth.\n"
"---\nname: brainerce-product-onboarding\ndescription: 'Add a product to a Brainerce store properly, from creating it through to category, tags, stock and publishing. Use when the merchant says add a product, list this item, put this in the shop, set up my new range, copy an existing product, or fix the stock count on something. Also covers duplicating a product, publishing the whole catalog to a storefront, stock corrections and stock history. For store owners, not developers. A price or description edit on a set-up product needs no sequence. Not for reviews (brainerce-analytics), finding drafts (brainerce-store-health) or variant versus custom field (brainerce-store-architecture). Keywords: add product, new product, create product, stock count, inventory, restock, categorise, tags, publish, publish all, duplicate product, bulk import, CSV import, product images, alt text, stock history, sale price dates.'\ncompatibility: ChatGPT, Claude Code, Claude Desktop, Cursor\nmaintainer: Brainerce\nmetadata:\n author: Brainerce\n version: '1.0.0'\n---\n\n⛔ **Before you call anything a dashboard task, look for `search_tools` in your tool list.** Some connections carry a small curated list PLUS a way to reach everything else. Where `search_tools` exists, search for what the merchant asked for and call any hit through the `call_read_tool` / `call_write_tool` / `call_destructive_tool` it names. The dashboard is the honest answer only when your list has no `search_tools`, or the search comes back empty. A few things are refused through it deliberately (payment provider setup, refunds and recording payments, gift cards), which is why an empty result there is a real answer rather than a gap.\n\nGet a new product from \"I have this thing to sell\" to a listing customers can actually find and buy.\n\n## Core principle\n\nA created product is not a finished product. A merchant who is told \"done\" and then finds the item invisible on their own storefront, uncategorised, or with no stock, has been misled. Walk the whole sequence, and say which parts you skipped.\n\n## When to use this skill first\n\n- \"Add a product\", \"I have something new to sell\", \"list this\".\n- \"Set up my new range\" or several products at once.\n- \"Make another one like this\": duplicating an existing listing.\n- \"Fix the stock on X\", \"I counted 40 of these\".\n\n## When NOT to use this skill first\n\n- Changing a price or a description on an existing, fully set up product: just do it, no sequence needed.\n- \"What do people think of this product\", ratings and reviews: use `brainerce-analytics`.\n- \"Find products I left as drafts\": use `brainerce-store-health`.\n- \"Put this product on sale\": use `brainerce-launch-a-sale`.\n- \"Should size be a variant or an option\", or any question about how the catalog should be modelled before the product exists: use `brainerce-store-architecture`.\n\n---\n\n## The sequence\n\nDo these in order. Later steps depend on earlier ones, and skipping one is how products end up invisible.\n\n### 1. Look before you create\n\nCall `list_products` with the name the merchant gave. If something close already exists, say so and ask whether they want a new product or an edit to that one. Creating a near-duplicate is easy to do and annoying to undo, and on the ChatGPT app there is no delete tool to clean it up with.\n\nIf the merchant wants something very like an existing product, `duplicate_product` is faster and less error prone than retyping everything. Duplicate first, then edit the differences with `update_product`.\n\n### 2. Create it\n\nCall `create_product`. Ask for what is missing rather than filling it in yourself:\n\n- **Name** and **price**, always. Read the currency from `get_store`; do not assume.\n- **Description**: offer to draft one, but show it to the merchant before it goes live. This is their voice, on their storefront.\n- **A photo the merchant attached to the chat**: on the ChatGPT app there is no route for it. The receiving field was withdrawn on 2026-09-23 after the submission portal refused the tool scan over its metadata, so do not promise it and do not invent a `download_url`. Ask for a direct image FILE URL instead and pass it in `images`. On the full connector the attachment route still exists.\n- **Images by URL**: on the full connector the fast route is `ingest_media_asset({ sourceUrl })` first, then pass what it returns as `{ url, key }`. That image is on the Brainerce CDN and shows up straight away. A bare external URL also works everywhere, but it is only **queued** for download and stays hidden from the storefront, the cart and the checkout until it lands. The URL has to point at an actual image file (`.jpg`, `.png`, `.webp`); a link to a page that merely displays a photo, like a stock-photo listing, downloads as HTML and is dropped.\n ⛔ The response echoes an `importStatus` per image. `pending` means queued and **not yet live**, so report it as queued, never as done. A failure that happens later will not be in that response either; re-read the product with `get_product` to see it.\n- **Stock, at creation time**: for a SIMPLE product `create_product` takes `inventory: { total }` inline. Set it here. ⛔ For a product with variants that product-level field is ignored: each entry in `variants` carries its own `inventory` (a plain number), so put the opening count on every variant, or you get a product whose every size reads 0. See step 5.\n- **Variants**: sizes, colours, materials. Ask if the product obviously has them (\"a t-shirt\" almost certainly does) and do not silently create a single-variant product for something that needs five.\n- ⛔ **Downloads are a separate two-step, and not on the ChatGPT app.** `create_product` and `update_product` silently drop the download fields rather than refusing, so passing `isDownloadable` gives you a product that looks created and sells nothing. Never rely on it. On the full connector (Claude, or an API key) create the product first as an ordinary item, then `search_tools \"digital download file\"` and call `ingest_download_file({ sourceUrl })` with a public direct link to the file, then `set_product_download_files({ productId, fileKeys })` with the `fileKey` it returned. The second call is destructive, so the host asks the merchant to approve it. Tell the merchant the limits before you start: 50MB per file, no plain text or CSV (zip it), a simple product only (variable products and kits take files per variant in the dashboard), nothing is scanned for malware, and attaching does not touch stock tracking, so read `result.note` and relay it if the product still cannot be bought. On the ChatGPT app none of this exists: say it is a dashboard job before you call any tool.\n\n### 3 and 4. Category and tags, in the same call\n\n**Do this inline on `create_product` rather than as four separate calls.** It takes three fields:\n\n- `categoryNames`: category names to put it in. Matched case-insensitively against what already exists, and created if nothing matches.\n- `brandNames`: same behaviour for the brand.\n- `tags`: tag names. Same again, resolved or created case-insensitively.\n\nSo \"a ceramic mug in Kitchen, tagged handmade and gift\" is one call with `categoryNames: [\"Kitchen\"]` and `tags: [\"handmade\", \"gift\"]`, not a list, a create, a list and a create. Case-insensitive matching is what stops \"Summer\" landing next to \"summer\".\n\nIf you already hold real category ids, `categories` and `brands` take ids instead, and unknown ids are rejected rather than created.\n\n**The category page itself.** `update_category` writes the page copy a storefront shows: `description` (long-form HTML) and `metaDescription` (the page's meta description, 50 to 160 characters), and it can pin the Google product taxonomy id with `googleTaxonomyId` (a number pins it; `null` clears the pin and it is worked out from the name again). Each takes `null` to clear. For a category with no copy, `list_seo_category_gaps` lists them worst first, and `generate_seo_category_description` writes and saves one from the products in it.\n\n⛔ **`list_categories`, `create_category`, `list_tags` and `create_tag` are OAuth-only.** A merchant connected with a `brainerce_` API key gets \"This tool requires OAuth authentication and is not available via API key\" from every one of them. That is not a store problem and it is not worth retrying. The inline `categoryNames` / `tags` fields above go through `create_product` and work on either connection, which is the other reason they are the default route here.\n\n### 5. Set stock, and mind which kind of product it is\n\nA product with no stock is not buyable, and a merchant who thinks they have listed something for sale will not check. If the merchant has not said how many, ask; do not default to a number.\n\n- **Simple product**: `set_product_stock` sets the absolute total. It also accepts `product` as a name or slug instead of `productId`, and it refuses rather than guessing if the name matches more than one product.\n- **Product with variants**: ⛔ **`set_product_stock` is for SIMPLE products only.** Called on a variant product it does not refuse and it does not warn. It writes a product-level stock row, but a variant product's stock is reported as the **sum of its variants** and that row is never read back, so the number you set simply never becomes the answer. You get a success and no change the merchant can see. Set the opening stock per variant in `variants[].inventory` on `create_product` at step 2, or change one afterwards with `set_variant_stock`.\n- **Changing one variant's stock afterwards** is `set_variant_stock`: `variantId` comes from `get_product`, `newTotal` is the absolute count. It is on the ChatGPT app's curated list (since 2026-09-15) as well as the full connector. If it is somehow not in your tool list, say plainly that per-variant stock is a dashboard job, under the product's variant editor, and do not reach for `set_product_stock` as a substitute: on a variant product that call succeeds and changes nothing the merchant can see.\n- **Kit** (`type: 'KIT'`, a gift box or set assembled from other products): ⛔ **a kit has no stock of its own and there is no number to set.** `set_product_stock` on a kit is **refused** with an explanation rather than half-working. How many kits can be sold is worked out from the contents (the component that runs out first decides), so the way to make a kit sellable is to stock its components, not the kit. `get_kit_components` reports that figure as `available`; `get_product_inventory` will not answer for a kit, because there is no row to read.\n\n ⛔ **`create_product` with `type: 'KIT'` creates an EMPTY kit, and an empty kit cannot be bought.** The create succeeds and the product looks normal, but until it has contents it has no price and a shopper's add-to-cart is refused. Follow it with **`set_kit_components`** in the same breath, or you have handed the merchant a dead product. ⛔ That tool **REPLACES** the whole list rather than appending, so when you are editing an existing kit, read it with `get_kit_components` first and send back every component it should end up with. A `VARIABLE` component needs its `componentVariantId` pinned; a kit cannot contain another kit.\n\n `set_kit_components` is **not on the ChatGPT app's curated list**. If it is not in your tool list, do not present a created kit as finished: say plainly that the kit still needs its contents and that adding them is a dashboard job (open the kit, then its contents list) or an admin-API one (`PUT /v1/products/{id}/kit-components`, SDK `setKitComponents`).\n\n `kitPricingMode` **is** settable here, on `create_product` and `update_product`, alongside `kitDiscountValue`. `FIXED` (the default) charges the `basePrice` you set and it stays put. `SUM` makes the kit cost exactly what its contents cost, recomputed on every read, so a component going on sale lowers the kit price on its own. `SUM_MINUS_PERCENT` is that sum less `kitDiscountValue` percent (0-100). ⛔ On the two SUM modes the `basePrice` you passed is a **placeholder that is never charged** — say so, or the merchant will think the number they gave you is the price.\n\n`get_product_inventory` reads back what is actually there, and is the tool for a stock take correction as well. For a variant product its `inventory` total is already summed across the variants.\n\n### 6. Offer to publish, do not assume\n\nProducts can exist as drafts. Tell the merchant which state it is in and ask before making it visible. \"Do you want this live on the storefront now, or held as a draft while you add photos?\" is one sentence and prevents both of the bad outcomes.\n\n**Visible on the storefront needs two things, and creating gives you at most one.** The product's `status` must be `active` (the default; a `draft` never shows), **and** the product must be published to the sales channel the storefront reads from. `create_product` does not publish. ⛔ **Its `platforms` field is not a publish path either**: it expects a channel record id with a literal `vc:` prefix, so a `vc_` connection id or a channel name matches nothing, the call still reports success, and the product stays invisible. `update_product` has no `platforms` field at all. The publish route is `publish_product_to_channel`, which takes the channel's `vc_` id, its id from `list_sales_channels`, or its exact name, and it is on the ChatGPT app's curated list as well as the full connector. It is OAuth-only: on a `brainerce_` API-key connection it refuses, and publishing is then a dashboard step (Products → the product → sales channels). Call it once per product after creating, or ask which channel when the store has more than one. A merchant who says \"I added it but the shop is empty\" is almost always missing this step, and `list_products` with `salesChannelId` shows what is actually live.\n\n**Many products at once.** Publish a catalog: `bulk_update_platforms({ filter: { status: 'active' }, vcPublishTo: [channel] })`; `vcPublishTo` accepts the channel id, its `vc_` id or its name. `filter: { status: 'active' }` is the \"all my products\" form (an empty filter is refused), `productIds` scopes it to a list, `vcUnpublishFrom` is the reverse, and it changes visibility only. A large catalog is queued and the result carries `{ queued: true, jobId }`: report it as in progress and poll `get_bulk_job_status`, do not call it again. It is on the ChatGPT app's curated list since 2026-09-15, and unlike the single publish it also works on a `brainerce_` API key with `products:write`, so on an API-key connection it is the publish route. `set_product_channel_app_visibility` (full connector) hides one product from a connector app such as Google Merchant Center without unpublishing it from the storefront, which is a different thing.\n\n## The media library\n\nImages live in a reusable library rather than only on the product, and merchants ask about it as \"my photos\" or \"the images I already uploaded\". On the full connector:\n\n- `ingest_media_asset` pulls an external URL onto the Brainerce CDN and hands back the `{ url, key }` to attach. This is the route that makes an image show up immediately.\n- `list_media_assets` and `list_media_assets_advanced` browse what is already uploaded, `get_media_asset` reads one, and `get_media_asset_usage` says which products are using it, which is the check to run before removing anything.\n- `set_media_asset_alt` writes alt text, which is what the SEO score on the products table is asking for.\n- `list_media_folders`, `create_media_folder` and `move_media_assets` organise them.\n\nNone of these are on the ChatGPT app's curated list. Check your tool list before offering any of it, and point at the dashboard's Media section otherwise. ⛔ And the attached-photo route is NOT a way around that on the ChatGPT app: a merchant who drops a photo into the conversation still needs to give you a direct image URL, or upload it in the dashboard.\n\n## Stock beyond the count\n\nFour inventory tools arrived on the full connector on 2026-09-15; none of them are on the ChatGPT app.\n\n- `get_inventory_history` is the movement ledger for one product or variant: every change with its delta, the balance before and after, who made it and the order behind it. It is the answer to \"why does this say 3 when I counted 10\".\n- `get_stock_velocity` is units per day over 7, 30 or 90 days, fastest first. Only products that sold at least one unit appear, so a product missing from it sold nothing, which is not the same as being out of stock.\n- `upsert_channel_inventory_policy` reserves part of the shared stock pool for one sales channel; it does not add or remove stock. `trigger_inventory_sync` pushes the current count out to connected platforms in the background. The policy is per product or variant and per channel: `protectedQuantity` units that no other channel may sell, 0 removes it, and it is refused when the item is not tracked or the figure exceeds what is left after the other channels' reservations. `list_channel_inventory_policies` shows the split and `delete_channel_inventory_policy` clears one. A completed order from a channel takes its units off that channel's own `protectedQuantity` first, so the figure shrinks as the channel sells and the other channels' shares stay whole; cancelled or refunded units go back to the shared pool, not to the share. Every cart, checkout and order refuses a line that does not fit in what the channel may sell, and `getProduct` / `getProducts` / `getInventory` on a channel show that number, not the whole pool. The sync is one-way and outbound (Shopify, WooCommerce and the like), overwrites the count they hold, and is refused when no installed connector can receive inventory; it is not a stock change and not a pull.\n\nWarehouses, suppliers and purchase orders have no tool on any connection and stay in the dashboard under Inventory.\n\n## Two product fields worth knowing\n\nBoth are on `create_product` and `update_product` on every connection since 2026-09-15:\n\n- **A sale-price window.** `salePriceStartsAt` and `salePriceEndsAt` (ISO 8601) schedule a sale price. Set both or neither; a lone bound is ignored. This is a product-level sale, which is the right tool for \"this item is on offer this month\"; a store-wide or category-wide sale is a discount rule, in `brainerce-launch-a-sale`. One variant can carry its own window (same two fields, same rules, overrides the product's) on `create_variant`, `update_variant` and `bulk_save_variants`; `null` clears a bound, and in `bulk_save_variants` an omitted bound keeps the stored one. The window is enforced everywhere: the storefront, cart and checkout use the regular price before the start and after the end, and the same dates reach the Google and Meta feeds, so the merchant does NOT need to clear the sale price when the sale is over. A variant with a sale price but no dates of its own follows the product's dates.\n- **Shipping weight and dimensions.** `shippingWeightValue` with `shippingWeightUnit`, and `shippingLengthValue`, `shippingWidthValue`, `shippingHeightValue` with `shippingDimensionUnit`. Weight-based shipping rates and carrier label quotes read these, so a product without a weight ships at the rate's base cost and cannot be quoted at a carrier. Ask for them when the store charges by weight.\n\n## Response shape\n\n> ✓ Ceramic Mug is created at 65 ILS, in Kitchen, tagged handmade and gift, with 40 in stock.\n>\n> It is currently a draft, so customers cannot see it yet.\n>\n> Want me to publish it, or would you rather add photos first?\n\n**Partly done, use this shape:**\n\n> ✓ Ceramic Mug is created at 65 ILS with 40 in stock.\n>\n> Two things I did not do: it is not in a category yet, and it has no images. Uncategorised products are hard for customers to find.\n>\n> Want me to put it in Kitchen?\n\n## Rules\n\n- Never say \"added to your store\" for a draft. Say it is a draft and what that means. Never say \"on your storefront\" for a product you have not published to the channel with `publish_product_to_channel`.\n- **When the merchant asks what is still missing, how to start selling, or whether the shop is ready, call `get_store_setup_status` first** (on the ChatGPT connector and the full connector) and answer from its checklist, not from general e-commerce knowledge. It reports the store name, sales channel, products published to a channel, shipping, payment provider and tax, each with a `nextAction`. A payment provider in test mode counts as not done.\n- Check `list_products` before creating. For categories and tags, pass `categoryNames` and `tags` on `create_product` and let the case-insensitive match do the de-duplicating; do not call `list_categories` or `list_tags` first, because they are OAuth-only and fail outright on an API-key connection.\n- Ask for stock rather than defaulting to zero or to some number you picked.\n- Show generated descriptions to the merchant before publishing. This is their shop's voice.\n- `create_product` reaches an external origin when it downloads images from URLs, and running it twice creates two products, not one. If a call is ambiguous about whether it went through, check with `list_products` rather than re-running it.\n- `update_product` replaces the fields it touches rather than merging into them. Read the current product with `get_product` before an edit so you know what you are about to overwrite.\n- Several products at once: **check your tool list for `bulk_create_products` first.** It exists on the full connector and is the right tool for a CSV, a supplier list or a migration; looping `create_product` a thousand times is the exact thing it replaces. It is queued, so it returns a `jobId` and the products appear over the following seconds or minutes: report it as **started**, not finished, then poll `get_bulk_create_products_status` with that `jobId`. Re-sending a batch is safe, because a row whose SKU or `externalId` already exists is skipped rather than duplicated.\n- If `bulk_create_products` is not in your tool list, which is the case on the ChatGPT app's curated list, do them one at a time and report as you go. A half-finished batch is worse than a slow one.\n- Deleting a product: `delete_product` exists on the full connector but is not on the ChatGPT app's curated list. If it is not in your tool list, say deletion is a dashboard job rather than saying the platform cannot do it.\n\n## Cross-skill connections\n\n- Putting the new product on sale: `brainerce-launch-a-sale`.\n- Reviews and ratings on it: `brainerce-analytics`.\n- Finding old drafts and out-of-stock items across the store: `brainerce-store-health`.\n- Deciding variant versus custom field, or category versus tag: `brainerce-store-architecture`.\n- Filling in a custom field on the new product: `brainerce-custom-fields`.\n\nRoute once, and do not bounce back and forth.\n"Full snapshot data
{
"description": "Add a product to a Brainerce store properly, from creating it through to category, tags, stock and publishing. Use when the merchant says add a product, list this item, put this in the shop, set up my new range, copy an existing product, or fix the stock count on something. Also covers duplicating a product, publishing the whole catalog to a storefront, stock corrections and stock history. For store owners, not developers. A price or description edit on a set-up product needs no sequence. Not for reviews (brainerce-analytics), finding drafts (brainerce-store-health) or variant versus custom field (brainerce-store-architecture). Keywords: add product, new product, create product, stock count, inventory, restock, categorise, tags, publish, publish all, duplicate product, bulk import, CSV import, product images, alt text, stock history, sale price dates.",
"included_files": [
{
"relative_path": "agents/openai.yaml",
"size_in_bytes": 1102
},
{
"relative_path": "assets/icon.png",
"size_in_bytes": 3208
}
],
"name": "brainerce-product-onboarding",
"skill_md_contents": "---\nname: brainerce-product-onboarding\ndescription: 'Add a product to a Brainerce store properly, from creating it through to category, tags, stock and publishing. Use when the merchant says add a product, list this item, put this in the shop, set up my new range, copy an existing product, or fix the stock count on something. Also covers duplicating a product, publishing the whole catalog to a storefront, stock corrections and stock history. For store owners, not developers. A price or description edit on a set-up product needs no sequence. Not for reviews (brainerce-analytics), finding drafts (brainerce-store-health) or variant versus custom field (brainerce-store-architecture). Keywords: add product, new product, create product, stock count, inventory, restock, categorise, tags, publish, publish all, duplicate product, bulk import, CSV import, product images, alt text, stock history, sale price dates.'\ncompatibility: ChatGPT, Claude Code, Claude Desktop, Cursor\nmaintainer: Brainerce\nmetadata:\n author: Brainerce\n version: '1.0.0'\n---\n\n⛔ **Before you call anything a dashboard task, look for `search_tools` in your tool list.** Some connections carry a small curated list PLUS a way to reach everything else. Where `search_tools` exists, search for what the merchant asked for and call any hit through the `call_read_tool` / `call_write_tool` / `call_destructive_tool` it names. The dashboard is the honest answer only when your list has no `search_tools`, or the search comes back empty. A few things are refused through it deliberately (payment provider setup, refunds and recording payments, gift cards), which is why an empty result there is a real answer rather than a gap.\n\nGet a new product from \"I have this thing to sell\" to a listing customers can actually find and buy.\n\n## Core principle\n\nA created product is not a finished product. A merchant who is told \"done\" and then finds the item invisible on their own storefront, uncategorised, or with no stock, has been misled. Walk the whole sequence, and say which parts you skipped.\n\n## When to use this skill first\n\n- \"Add a product\", \"I have something new to sell\", \"list this\".\n- \"Set up my new range\" or several products at once.\n- \"Make another one like this\": duplicating an existing listing.\n- \"Fix the stock on X\", \"I counted 40 of these\".\n\n## When NOT to use this skill first\n\n- Changing a price or a description on an existing, fully set up product: just do it, no sequence needed.\n- \"What do people think of this product\", ratings and reviews: use `brainerce-analytics`.\n- \"Find products I left as drafts\": use `brainerce-store-health`.\n- \"Put this product on sale\": use `brainerce-launch-a-sale`.\n- \"Should size be a variant or an option\", or any question about how the catalog should be modelled before the product exists: use `brainerce-store-architecture`.\n\n---\n\n## The sequence\n\nDo these in order. Later steps depend on earlier ones, and skipping one is how products end up invisible.\n\n### 1. Look before you create\n\nCall `list_products` with the name the merchant gave. If something close already exists, say so and ask whether they want a new product or an edit to that one. Creating a near-duplicate is easy to do and annoying to undo, and on the ChatGPT app there is no delete tool to clean it up with.\n\nIf the merchant wants something very like an existing product, `duplicate_product` is faster and less error prone than retyping everything. Duplicate first, then edit the differences with `update_product`.\n\n### 2. Create it\n\nCall `create_product`. Ask for what is missing rather than filling it in yourself:\n\n- **Name** and **price**, always. Read the currency from `get_store`; do not assume.\n- **Description**: offer to draft one, but show it to the merchant before it goes live. This is their voice, on their storefront.\n- **A photo the merchant attached to the chat**: on the ChatGPT app there is no route for it. The receiving field was withdrawn on 2026-09-23 after the submission portal refused the tool scan over its metadata, so do not promise it and do not invent a `download_url`. Ask for a direct image FILE URL instead and pass it in `images`. On the full connector the attachment route still exists.\n- **Images by URL**: on the full connector the fast route is `ingest_media_asset({ sourceUrl })` first, then pass what it returns as `{ url, key }`. That image is on the Brainerce CDN and shows up straight away. A bare external URL also works everywhere, but it is only **queued** for download and stays hidden from the storefront, the cart and the checkout until it lands. The URL has to point at an actual image file (`.jpg`, `.png`, `.webp`); a link to a page that merely displays a photo, like a stock-photo listing, downloads as HTML and is dropped.\n ⛔ The response echoes an `importStatus` per image. `pending` means queued and **not yet live**, so report it as queued, never as done. A failure that happens later will not be in that response either; re-read the product with `get_product` to see it.\n- **Stock, at creation time**: for a SIMPLE product `create_product` takes `inventory: { total }` inline. Set it here. ⛔ For a product with variants that product-level field is ignored: each entry in `variants` carries its own `inventory` (a plain number), so put the opening count on every variant, or you get a product whose every size reads 0. See step 5.\n- **Variants**: sizes, colours, materials. Ask if the product obviously has them (\"a t-shirt\" almost certainly does) and do not silently create a single-variant product for something that needs five.\n- ⛔ **Downloads are a separate two-step, and not on the ChatGPT app.** `create_product` and `update_product` silently drop the download fields rather than refusing, so passing `isDownloadable` gives you a product that looks created and sells nothing. Never rely on it. On the full connector (Claude, or an API key) create the product first as an ordinary item, then `search_tools \"digital download file\"` and call `ingest_download_file({ sourceUrl })` with a public direct link to the file, then `set_product_download_files({ productId, fileKeys })` with the `fileKey` it returned. The second call is destructive, so the host asks the merchant to approve it. Tell the merchant the limits before you start: 50MB per file, no plain text or CSV (zip it), a simple product only (variable products and kits take files per variant in the dashboard), nothing is scanned for malware, and attaching does not touch stock tracking, so read `result.note` and relay it if the product still cannot be bought. On the ChatGPT app none of this exists: say it is a dashboard job before you call any tool.\n\n### 3 and 4. Category and tags, in the same call\n\n**Do this inline on `create_product` rather than as four separate calls.** It takes three fields:\n\n- `categoryNames`: category names to put it in. Matched case-insensitively against what already exists, and created if nothing matches.\n- `brandNames`: same behaviour for the brand.\n- `tags`: tag names. Same again, resolved or created case-insensitively.\n\nSo \"a ceramic mug in Kitchen, tagged handmade and gift\" is one call with `categoryNames: [\"Kitchen\"]` and `tags: [\"handmade\", \"gift\"]`, not a list, a create, a list and a create. Case-insensitive matching is what stops \"Summer\" landing next to \"summer\".\n\nIf you already hold real category ids, `categories` and `brands` take ids instead, and unknown ids are rejected rather than created.\n\n**The category page itself.** `update_category` writes the page copy a storefront shows: `description` (long-form HTML) and `metaDescription` (the page's meta description, 50 to 160 characters), and it can pin the Google product taxonomy id with `googleTaxonomyId` (a number pins it; `null` clears the pin and it is worked out from the name again). Each takes `null` to clear. For a category with no copy, `list_seo_category_gaps` lists them worst first, and `generate_seo_category_description` writes and saves one from the products in it.\n\n⛔ **`list_categories`, `create_category`, `list_tags` and `create_tag` are OAuth-only.** A merchant connected with a `brainerce_` API key gets \"This tool requires OAuth authentication and is not available via API key\" from every one of them. That is not a store problem and it is not worth retrying. The inline `categoryNames` / `tags` fields above go through `create_product` and work on either connection, which is the other reason they are the default route here.\n\n### 5. Set stock, and mind which kind of product it is\n\nA product with no stock is not buyable, and a merchant who thinks they have listed something for sale will not check. If the merchant has not said how many, ask; do not default to a number.\n\n- **Simple product**: `set_product_stock` sets the absolute total. It also accepts `product` as a name or slug instead of `productId`, and it refuses rather than guessing if the name matches more than one product.\n- **Product with variants**: ⛔ **`set_product_stock` is for SIMPLE products only.** Called on a variant product it does not refuse and it does not warn. It writes a product-level stock row, but a variant product's stock is reported as the **sum of its variants** and that row is never read back, so the number you set simply never becomes the answer. You get a success and no change the merchant can see. Set the opening stock per variant in `variants[].inventory` on `create_product` at step 2, or change one afterwards with `set_variant_stock`.\n- **Changing one variant's stock afterwards** is `set_variant_stock`: `variantId` comes from `get_product`, `newTotal` is the absolute count. It is on the ChatGPT app's curated list (since 2026-09-15) as well as the full connector. If it is somehow not in your tool list, say plainly that per-variant stock is a dashboard job, under the product's variant editor, and do not reach for `set_product_stock` as a substitute: on a variant product that call succeeds and changes nothing the merchant can see.\n- **Kit** (`type: 'KIT'`, a gift box or set assembled from other products): ⛔ **a kit has no stock of its own and there is no number to set.** `set_product_stock` on a kit is **refused** with an explanation rather than half-working. How many kits can be sold is worked out from the contents (the component that runs out first decides), so the way to make a kit sellable is to stock its components, not the kit. `get_kit_components` reports that figure as `available`; `get_product_inventory` will not answer for a kit, because there is no row to read.\n\n ⛔ **`create_product` with `type: 'KIT'` creates an EMPTY kit, and an empty kit cannot be bought.** The create succeeds and the product looks normal, but until it has contents it has no price and a shopper's add-to-cart is refused. Follow it with **`set_kit_components`** in the same breath, or you have handed the merchant a dead product. ⛔ That tool **REPLACES** the whole list rather than appending, so when you are editing an existing kit, read it with `get_kit_components` first and send back every component it should end up with. A `VARIABLE` component needs its `componentVariantId` pinned; a kit cannot contain another kit.\n\n `set_kit_components` is **not on the ChatGPT app's curated list**. If it is not in your tool list, do not present a created kit as finished: say plainly that the kit still needs its contents and that adding them is a dashboard job (open the kit, then its contents list) or an admin-API one (`PUT /v1/products/{id}/kit-components`, SDK `setKitComponents`).\n\n `kitPricingMode` **is** settable here, on `create_product` and `update_product`, alongside `kitDiscountValue`. `FIXED` (the default) charges the `basePrice` you set and it stays put. `SUM` makes the kit cost exactly what its contents cost, recomputed on every read, so a component going on sale lowers the kit price on its own. `SUM_MINUS_PERCENT` is that sum less `kitDiscountValue` percent (0-100). ⛔ On the two SUM modes the `basePrice` you passed is a **placeholder that is never charged** — say so, or the merchant will think the number they gave you is the price.\n\n`get_product_inventory` reads back what is actually there, and is the tool for a stock take correction as well. For a variant product its `inventory` total is already summed across the variants.\n\n### 6. Offer to publish, do not assume\n\nProducts can exist as drafts. Tell the merchant which state it is in and ask before making it visible. \"Do you want this live on the storefront now, or held as a draft while you add photos?\" is one sentence and prevents both of the bad outcomes.\n\n**Visible on the storefront needs two things, and creating gives you at most one.** The product's `status` must be `active` (the default; a `draft` never shows), **and** the product must be published to the sales channel the storefront reads from. `create_product` does not publish. ⛔ **Its `platforms` field is not a publish path either**: it expects a channel record id with a literal `vc:` prefix, so a `vc_` connection id or a channel name matches nothing, the call still reports success, and the product stays invisible. `update_product` has no `platforms` field at all. The publish route is `publish_product_to_channel`, which takes the channel's `vc_` id, its id from `list_sales_channels`, or its exact name, and it is on the ChatGPT app's curated list as well as the full connector. It is OAuth-only: on a `brainerce_` API-key connection it refuses, and publishing is then a dashboard step (Products → the product → sales channels). Call it once per product after creating, or ask which channel when the store has more than one. A merchant who says \"I added it but the shop is empty\" is almost always missing this step, and `list_products` with `salesChannelId` shows what is actually live.\n\n**Many products at once.** Publish a catalog: `bulk_update_platforms({ filter: { status: 'active' }, vcPublishTo: [channel] })`; `vcPublishTo` accepts the channel id, its `vc_` id or its name. `filter: { status: 'active' }` is the \"all my products\" form (an empty filter is refused), `productIds` scopes it to a list, `vcUnpublishFrom` is the reverse, and it changes visibility only. A large catalog is queued and the result carries `{ queued: true, jobId }`: report it as in progress and poll `get_bulk_job_status`, do not call it again. It is on the ChatGPT app's curated list since 2026-09-15, and unlike the single publish it also works on a `brainerce_` API key with `products:write`, so on an API-key connection it is the publish route. `set_product_channel_app_visibility` (full connector) hides one product from a connector app such as Google Merchant Center without unpublishing it from the storefront, which is a different thing.\n\n## The media library\n\nImages live in a reusable library rather than only on the product, and merchants ask about it as \"my photos\" or \"the images I already uploaded\". On the full connector:\n\n- `ingest_media_asset` pulls an external URL onto the Brainerce CDN and hands back the `{ url, key }` to attach. This is the route that makes an image show up immediately.\n- `list_media_assets` and `list_media_assets_advanced` browse what is already uploaded, `get_media_asset` reads one, and `get_media_asset_usage` says which products are using it, which is the check to run before removing anything.\n- `set_media_asset_alt` writes alt text, which is what the SEO score on the products table is asking for.\n- `list_media_folders`, `create_media_folder` and `move_media_assets` organise them.\n\nNone of these are on the ChatGPT app's curated list. Check your tool list before offering any of it, and point at the dashboard's Media section otherwise. ⛔ And the attached-photo route is NOT a way around that on the ChatGPT app: a merchant who drops a photo into the conversation still needs to give you a direct image URL, or upload it in the dashboard.\n\n## Stock beyond the count\n\nFour inventory tools arrived on the full connector on 2026-09-15; none of them are on the ChatGPT app.\n\n- `get_inventory_history` is the movement ledger for one product or variant: every change with its delta, the balance before and after, who made it and the order behind it. It is the answer to \"why does this say 3 when I counted 10\".\n- `get_stock_velocity` is units per day over 7, 30 or 90 days, fastest first. Only products that sold at least one unit appear, so a product missing from it sold nothing, which is not the same as being out of stock.\n- `upsert_channel_inventory_policy` reserves part of the shared stock pool for one sales channel; it does not add or remove stock. `trigger_inventory_sync` pushes the current count out to connected platforms in the background. The policy is per product or variant and per channel: `protectedQuantity` units that no other channel may sell, 0 removes it, and it is refused when the item is not tracked or the figure exceeds what is left after the other channels' reservations. `list_channel_inventory_policies` shows the split and `delete_channel_inventory_policy` clears one. A completed order from a channel takes its units off that channel's own `protectedQuantity` first, so the figure shrinks as the channel sells and the other channels' shares stay whole; cancelled or refunded units go back to the shared pool, not to the share. Every cart, checkout and order refuses a line that does not fit in what the channel may sell, and `getProduct` / `getProducts` / `getInventory` on a channel show that number, not the whole pool. The sync is one-way and outbound (Shopify, WooCommerce and the like), overwrites the count they hold, and is refused when no installed connector can receive inventory; it is not a stock change and not a pull.\n\nWarehouses, suppliers and purchase orders have no tool on any connection and stay in the dashboard under Inventory.\n\n## Two product fields worth knowing\n\nBoth are on `create_product` and `update_product` on every connection since 2026-09-15:\n\n- **A sale-price window.** `salePriceStartsAt` and `salePriceEndsAt` (ISO 8601) schedule a sale price. Set both or neither; a lone bound is ignored. This is a product-level sale, which is the right tool for \"this item is on offer this month\"; a store-wide or category-wide sale is a discount rule, in `brainerce-launch-a-sale`. One variant can carry its own window (same two fields, same rules, overrides the product's) on `create_variant`, `update_variant` and `bulk_save_variants`; `null` clears a bound, and in `bulk_save_variants` an omitted bound keeps the stored one. The window is enforced everywhere: the storefront, cart and checkout use the regular price before the start and after the end, and the same dates reach the Google and Meta feeds, so the merchant does NOT need to clear the sale price when the sale is over. A variant with a sale price but no dates of its own follows the product's dates.\n- **Shipping weight and dimensions.** `shippingWeightValue` with `shippingWeightUnit`, and `shippingLengthValue`, `shippingWidthValue`, `shippingHeightValue` with `shippingDimensionUnit`. Weight-based shipping rates and carrier label quotes read these, so a product without a weight ships at the rate's base cost and cannot be quoted at a carrier. Ask for them when the store charges by weight.\n\n## Response shape\n\n> ✓ Ceramic Mug is created at 65 ILS, in Kitchen, tagged handmade and gift, with 40 in stock.\n>\n> It is currently a draft, so customers cannot see it yet.\n>\n> Want me to publish it, or would you rather add photos first?\n\n**Partly done, use this shape:**\n\n> ✓ Ceramic Mug is created at 65 ILS with 40 in stock.\n>\n> Two things I did not do: it is not in a category yet, and it has no images. Uncategorised products are hard for customers to find.\n>\n> Want me to put it in Kitchen?\n\n## Rules\n\n- Never say \"added to your store\" for a draft. Say it is a draft and what that means. Never say \"on your storefront\" for a product you have not published to the channel with `publish_product_to_channel`.\n- **When the merchant asks what is still missing, how to start selling, or whether the shop is ready, call `get_store_setup_status` first** (on the ChatGPT connector and the full connector) and answer from its checklist, not from general e-commerce knowledge. It reports the store name, sales channel, products published to a channel, shipping, payment provider and tax, each with a `nextAction`. A payment provider in test mode counts as not done.\n- Check `list_products` before creating. For categories and tags, pass `categoryNames` and `tags` on `create_product` and let the case-insensitive match do the de-duplicating; do not call `list_categories` or `list_tags` first, because they are OAuth-only and fail outright on an API-key connection.\n- Ask for stock rather than defaulting to zero or to some number you picked.\n- Show generated descriptions to the merchant before publishing. This is their shop's voice.\n- `create_product` reaches an external origin when it downloads images from URLs, and running it twice creates two products, not one. If a call is ambiguous about whether it went through, check with `list_products` rather than re-running it.\n- `update_product` replaces the fields it touches rather than merging into them. Read the current product with `get_product` before an edit so you know what you are about to overwrite.\n- Several products at once: **check your tool list for `bulk_create_products` first.** It exists on the full connector and is the right tool for a CSV, a supplier list or a migration; looping `create_product` a thousand times is the exact thing it replaces. It is queued, so it returns a `jobId` and the products appear over the following seconds or minutes: report it as **started**, not finished, then poll `get_bulk_create_products_status` with that `jobId`. Re-sending a batch is safe, because a row whose SKU or `externalId` already exists is skipped rather than duplicated.\n- If `bulk_create_products` is not in your tool list, which is the case on the ChatGPT app's curated list, do them one at a time and report as you go. A half-finished batch is worse than a slow one.\n- Deleting a product: `delete_product` exists on the full connector but is not on the ChatGPT app's curated list. If it is not in your tool list, say deletion is a dashboard job rather than saying the platform cannot do it.\n\n## Cross-skill connections\n\n- Putting the new product on sale: `brainerce-launch-a-sale`.\n- Reviews and ratings on it: `brainerce-analytics`.\n- Finding old drafts and out-of-stock items across the store: `brainerce-store-health`.\n- Deciding variant versus custom field, or category versus tag: `brainerce-store-architecture`.\n- Filling in a custom field on the new product: `brainerce-custom-fields`.\n\nRoute once, and do not bounce back and forth.\n"
}SHA-256 of public snapshot: 1b2b54a68ccdf3a68196fa6068affa9e5bdda428457c36fc08acbc464352cfd7