Tools
What an assistant connected to Fabric can do, and what each action needs.
Each tool is one action an assistant can take — 33 of them, not one per API endpoint. A shorter list is one an assistant chooses from more accurately.
Start with list_brands. Every other tool takes a brandId, and there is no default and no
session to infer one from: an OAuth token resolves to a person, who may belong to several
organizations, so the caller names the brand and Fabric checks that claim against their membership.
A brand outside it answers not found rather than forbidden — telling a caller that a brand
exists is itself a leak.
A scope is necessary and never sufficient. The organization role is checked again inside every
operation, so a credential holding catalog:write still cannot do what its holder could not.
| Tool | Scope | What it does |
|---|---|---|
accept_category_suggestions | catalog:write | Accept the suggested category for products waiting in Needs mapping: each moves onto its suggestedCategory (as the product reads show it) and into the active catalog. Products with no suggestion are left in the queue. Use the ids a read returned, up to 500. |
add_list_products | catalog:write | Add products to an existing LIST. Adding the same product twice is harmless — membership is a set, and the reply says how many were already there. This does not work on a view: a view's membership is computed from its filters. Use a list id from list_cohorts or from a list created in this conversation. |
approve_enriched_value | catalog:write | Accept an AI-written value as correct, clearing the judge's flag on it. The value itself does not change — what changes is that somebody has vouched for it, which is what the product's flag count reflects. Refused for a value that was imported or typed by a person, because there is no AI judgement to clear. |
approve_product_description | catalog:write | Accept a description Fabric wrote as correct, clearing the judge's flag on it. The text does not change. Refused for a description that was imported or written by a person, because there is no AI judgement to clear. |
count_products_by_category | catalog:read | Count this brand's products in every category, exactly, on the server: each category's own count and the count in everything below it, ranked most first. Use it for any question about how many products a category holds or which holds the most, never by sampling products. scope is the catalog's Active tab (the default), its Needs mapping queue, or all live products. |
create_list | catalog:write | Create a LIST: a hand-picked set of products that no filter governs. Use it only when the merchant named the products, or when the set is a judgement no rule captures. If it can be stated as a rule, create a view instead — a list does not update itself. Products that cannot be enriched yet are left out and the reply says how many, so the list is a set someone can actually work through. Costs nothing and changes no product. Only product ids a tool in this conversation returned. |
create_view | catalog:write | Create a saved VIEW: a catalog tab whose membership is COMPUTED from filters and updates itself as the catalog changes. Use it for anything describable as a rule — 'products missing a material', 'everything in Outerwear'. Membership is not hand-picked and cannot be; the filters decide, so there is no way to add a product to a view. Costs nothing and changes no product. Only ids a tool in this conversation returned. |
decide_data_sourcing_rows | catalog:write | Promote or demote rows of a Data Sourcing run, by observationId from get_data_sourcing_results, with a reason that is saved as the audit and cannot start with auto-promoted:. PROMOTE writes the page's attributes, images and description onto the product and SPENDS ONE CREDIT per product — do it only when the merchant has said so for these rows, or when a run's review row plainly matches the product and they asked you to work through the run. The description replaces the product's own, whoever wrote it, and the next enrichment run rewrites it from the page's text. DEMOTE of the page a product's data came from removes that data, puts back the description the promote replaced, and refunds the credit. Rows are decided one by one: the reply names each row it did not take and why. overrides per observationId drops names or corrects values before promoting. The description is one of those names (Description): drop it to keep the product's own, or correct it with plain text, which is kept exactly as typed and which enrichment does not rewrite. |
get_attribute | catalog:read | One attribute's full definition, by id, key or name: its type, scope, kind, format instructions and, for an Enum, EVERY allowed value. Read it before proposing or writing a value, and trust it over anything else: list_attributes is capped and may not show the attribute you need, and an analysis is not a definition. |
get_credit_balance | catalog:read | Read this brand's credit balance. Costs nothing and changes nothing. Use this to answer a question about credits, and before suggesting work that would spend them. |
get_data_sourcing_results | catalog:read | Read what a Data Sourcing run found, one row per product searched: the grader's verdict (outcome), the attributes read with their confidence and source page, the images, the last decision a person made, and where the row stands now (filed). Each row carries the observationId a decision names. Costs nothing. Narrow with outcome and follow nextCursor rather than raising limit. A review row is a find waiting for a person; a rejected row is a miss or a page a person turned down, and never product data. A row with decidedBy of gate:no_gold_match was never searched: its category has no golden mapping. |
get_data_sourcing_run | catalog:read | Read one Data Sourcing run by id: its status, how many products it has searched, how many rows the grader filed as promote, review or reject, and how a person has since decided them (promoted, reviewing, rejected, refused). Costs nothing. A review row is a find waiting for a decision — the merchant's on reviewUrl, or yours through decide_data_sourcing_rows when they asked you to work the run. |
get_enrichment_run | catalog:read | Read the status and counts of one enrichment run: how many products are done, succeeded, failed or skipped. Costs nothing. Use the run id from a run that was started in this conversation. |
get_export | catalog:read | Check on an export. While it runs there is no download link; once it is completed the reply carries the path to fetch it from. Use the exportId a start_export in this conversation returned. |
get_list_products | catalog:read | Read the products in a hand-picked LIST — its members as they stand, Active products only. Use it to turn a list the merchant names into product ids before enriching, sourcing, exporting or describing it. Resolve the list's id with list_cohorts first. |
get_product_content | catalog:read | Read everything one product SAYS: its description (with who wrote it, and the merchant's original beside it), every attribute value with the judge's confidence and reasoning, its FAQ entries and its image alt text. Costs nothing. Use this whenever asked what a product says, what it is made of, why a value was written, or whether a value can be trusted — get_product answers none of that. Takes a product id a tool in this conversation returned; search by SKU first if you have only a code. |
get_product | catalog:read | Read one product's identity: title, SKU, category (and suggestedCategory, the import's proposal, while it waits in Needs mapping), enrichment status, flag count and lead image, with its description. Use this to resolve an id — free-text search does not match ids. It returns NO attribute values and no FAQ entries: get_product_content reads those, so never tell the merchant what a product says on the strength of this call. |
get_view_products | catalog:read | Read the products a VIEW currently selects — its live membership, recomputed from its filters. Use it to check what a view actually caught before telling the merchant it is right. A view that filters on updatedAt or on a per-variant attribute cannot be evaluated here and answers so explicitly; that means this read is unavailable, NOT that the view is broken. For a LIST, use get_list_products. |
list_attributes | catalog:read | List this brand's attribute definitions — the vocabulary its catalog is described in. extract says whether enrichment may write each one, which is what decides a run's cost. The list is capped and may be cut: for one attribute's full definition and allowed values, use get_attribute. |
list_brands | — | List the brands you can act on, with the organization each belongs to. Every other tool takes a brandId and there is no default, so call this first. Costs nothing and changes nothing. |
list_categories | catalog:read | List this brand's categories, flat, each with its parentId and whether it is a leaf. The tree is derived by walking parents and is never stored. A product may only sit on a LEAF — a category with no children — so leaf: false marks a category whose products are waiting to be re-filed. |
list_cohorts | catalog:read | List this brand's saved cohorts: its VIEWS (membership computed from filters) and its LISTS (hand-picked membership). Costs nothing. Use it to resolve the id of a cohort the merchant names, before reading a view's or a list's products, or changing a list's membership. |
list_data_sourcing_runs | catalog:read | List this brand's Data Sourcing runs, newest first, counted the way the Studio's run list counts them: a person's decision on a row outranks the grader's verdict. Costs nothing. Use it to find a run id or to see what is waiting for review. |
list_guidelines | catalog:read | List this brand's saved rules — what the enricher has been told to follow, and which of them are currently applied. Costs nothing. Read this before proposing a new rule, so you can tell the merchant whether one already covers what they asked for. |
load_skill | catalog:read | Load one of the procedures listed under Skills: which tools open that flow, where each fact must come from, and what not to claim. Costs nothing and changes nothing. Call it in the same round as your first read, not after you have already answered. |
plan_data_sourcing | catalog:read | Plan Data Sourcing for products you name: a search of supplier and trusted retailer pages for their attributes, images and descriptions. Answers how many of them can be sourced, which cannot and the fix for each, and a quoteId. Costs nothing and starts NOTHING — it is the step a merchant takes in the Studio by reading a card. Call it before start_data_sourcing, and tell the merchant what is left out and why. Only product ids a tool returned. |
remove_list_products | catalog:write | Remove products from a LIST. It takes them out of that hand-picked set only — it does not archive or delete a product, and it changes nothing about the catalog. Use a list id from list_cohorts or from a list created in this conversation. |
search_products | catalog:read | Search this brand's products. Filters use the same grammar a saved View stores — repeat filter as <field>:<operator>:<value>. The fields are: enrichmentStatus (values: not_enriched, enriching, in_review, ready_to_publish, published), category (a category id), supplier (values: data, no_vendor_sku), pendingGuidance, and attr:<attributeId>. Operators are is, isNot, empty, notEmpty. So products nothing has enriched yet are enrichmentStatus:is:not_enriched. Set bucket: "active" when the products are for work — anything else can include products in the Needs-mapping queue, which no run will touch, so asking for 5 and getting 5 is only true in the active catalog. A product in Needs mapping can carry suggestedCategory (id, path): the category its import proposed, which accept_category_suggestions moves it onto. Returns one page and a cursor — follow the cursor rather than raising the limit. A result of 0 means the filter matched nothing, not that the catalog lacks the product. |
set_attribute_value | catalog:write | Set one product's value for one attribute. This marks the value as EDITED, which means enrichment will preserve it rather than overwrite it, and it drops any AI reasoning attached to the old value. Use the exact attributeId and productId a read returned — never one you inferred. Changes one product only; there is no bulk form. |
set_product_description | catalog:write | Set one product's description — the one text every destination publishes, the store included where native writes are on. This marks it EDITED, so enrichment will never overwrite it, and drops the AI reasoning behind the old text; the merchant's original stays beside it untouched. An empty description clears it. Use the productId a read returned. Changes one product only. |
set_review_status | catalog:write | Move products through review. approve sends them from in-review to ready-to-publish and clears every judge flag on them; reopen sends them back. Products that are not in a state the transition applies to are REPORTED as skipped rather than refused, so a mixed set still moves the ones it can. |
start_data_sourcing | catalog:write | Start the Data Sourcing run plan_data_sourcing described, with the SAME productIds and its quoteId. Refused when the quote no longer matches — the selection or its eligibility changed — so plan again. The run searches in the background and spends nothing by itself; what it finds waits on the review screen (the reply's reviewUrl), where a person promotes rows onto products at one credit each. Calling this again with the same quote answers the run it already started rather than starting another. |
start_export | catalog:read | Start a catalog export. Answers immediately with a job to poll — the file is not ready when this returns. Scope it to a saved view or list; with neither it exports the whole catalog. Pass the SAME requestId if you retry, and the export will not start twice. |