Tools
What an assistant connected to Fabric can do, and what each action needs.
Each tool is one action an assistant can take — 21 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 |
|---|---|---|
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. |
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. |
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_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_product_content | catalog:read | Read everything one product SAYS: its description, 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, enrichment status, flag count and lead image. Use this to resolve an id — free-text search does not match ids. It returns NO attribute values, no description, 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. |
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. |
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 products or changing a list's membership. |
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. |
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. 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_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_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. |