AgentStack
Browse Sign in
Browse Why AgentStack Sell Docs
Sign in
SKILL verified MIT Self-run

Ucp

skill-shopify-ucp-cli-ucp · by Shopify

Use when the user wants to find, compare, buy, or track products from any online merchant. Covers cross-merchant catalog search ("find me X under $Y"), named-merchant transactions ("buy this from Z.com"), and order tracking. Trigger on shopping, products, prices, sellers, carts, checkout, orders, or any commercial intent. Falls back to merchant-hosted handoff when direct in-protocol checkout isn'…

No reviews yet
0 installs
31 views
0.0% view→install

Install

$ agentstack add skill-shopify-ucp-cli-ucp

✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.

Security review

✓ Passed

No issues found. Passed automated security review. · v0.1.0 How review works →

  • Prompt-injection patterns
  • Secret / credential exfiltration
  • Dangerous shell & filesystem operations
  • Untrusted network calls
  • Known-malicious package signatures

What it can access

  • Network access Used
  • Filesystem access No
  • Shell / process execution No
  • Environment & secrets No
  • Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

View the full security report →

Verified badge

Passed review? Show it. Paste this badge into your README, it links to the public security report.

AgentStack Verified badge Links to your public security report.
[![AgentStack Verified](https://agentstack.voostack.com/badges/verified.svg)](https://agentstack.voostack.com/security/report/skill-shopify-ucp-cli-ucp)

Reliability & compatibility

Security review passed
0 installs to date
no reviews yet
3mo ago

Declared compatibility

Claude CodeClaude Desktop

Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.

Preview Execution monitoring

We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.

How agent discovery & health will work →
Are you the author of Ucp? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

ucp

When a buyer expresses commercial intent — wanting to find, buy, or track products — this is your toolkit. You can search across thousands of merchants via a bundled global catalog, build carts and complete checkouts against any UCP-supporting merchant, and follow up on orders. For merchants that don't support direct transactions, hand off gracefully to the merchant's own flow.

> Setup: Run ucp profile init --name agent at the start of any session. It's idempotent — re-running with an existing profile no-ops (created: false, exit 0) — so call it unconditionally rather than checking state first. This creates the local CLI identity required for all UCP operations; it's not a merchant onboarding step or a Catalog API key. See references/SETUP.md for installation paths and ucp doctor.

How to decide what to do

| Buyer says... | Do this | |---|---| | "Find me X", "I need X for Y", "what's a good X under $Z" — no merchant named | ucp catalog search against the global catalog. Each result names its merchant via seller.domain. | | "Show me this" — buyer pastes a product/variant link or wants a specific product's full PDP/options matrix | ucp catalog get_product — single call, returns result.product (singular). Omit --business for global Catalog IDs. | | "Are these still available?" — refreshing prices/stock/validity for known IDs (saved lists, wish lists, stale carts) | ucp catalog lookup with the IDs (up to 50). To distinguish OOS from delisted, pass filters.available: false — the default filters to in-stock only, so OOS and delisted both look like absence. | | "Buy this from \" — buyer names a specific merchant | ucp discover --business first; if it succeeds, transact via --business . If it fails, the merchant doesn't speak UCP — tell the buyer and offer alternatives. | | "Track my order" | ucp order get --business |

Rule of thumb: broad product discovery → global catalog (no --business needed). Business-scoped operations — cart, checkout, order, or catalog scoped to a specific merchant — → pass --business . Reach for one or the other based on the buyer's intent.

Journey heuristics

  • Broad shopping request → search immediately with useful context. Don't ask clarifying questions first unless the request is impossible or unsafe.
  • Refinement ("cheaper", "different brand") → re-run search with a sharper query or filter; don't reuse stale results.
  • Comparison → lead with the key tradeoff (price vs feature, brand reputation vs cost), then cite concrete fields from the response.
  • Cart → low-commitment basket assembly. Pass context (locality signals: country, region, postal code; optional language/currency preference) on create when known — it lets the merchant localize currency, surface region-specific availability, and apply regional discounts.
  • Checkout → high-intent. Preserve request-shaped line_items on every update (line_items[].id targets the existing line; line_items[].item.id identifies the item/variant); introspect the merchant's schema before adding fields beyond the basics.
  • Order → read-only post-purchase status. Summarize fulfillment expectations and tracking events; don't invent return/reorder actions unless the response supports them.

Introspect first (capabilities + schemas)

The merchant decides what it accepts and what it exposes. These introspection commands save the agent from guessing:

  1. Merchant capabilitiesucp discover --business returns the operations and tools this merchant exposes (e.g. create_cart, update_checkout, plus any extensions). Use when the buyer names a specific merchant you don't know, or when you need to confirm a merchant supports an operation before composing it.
  1. Operation input schemaucp --input-schema --business returns the inputSchema for a specific tool from that merchant — including buyer-supplied destination fields, payment methods, discount handling, business-specific extension keys, etc. Use before composing any non-trivial payload (delivery info, payment, discount, fulfillment).
  1. What hits the wireucp [args] --dry-run builds and validates the request, then prints the exact MCP envelope (tool, arguments, auto-injected meta.idempotency-key and meta.ucp-agent) without dispatching. Use when debugging a payload, confirming a mutation before issuing it, or learning the protocol shape (e.g. while building your own UCP-aware app). The printed arguments are the canonical MCP call; the CLI additionally wraps signing and web-bot-auth at the transport layer — if you build a client that calls MCP directly, you own that wrapping.

The CLI rejects unknown plain keys client-side before sending; if you hit SCHEMA_VALIDATION_FAILED, the error's CTA tells you the exact --input-schema command to run. Spec-canonical fields (per the UCP Context and Buyer types) may still be rejected if a specific merchant doesn't advertise them — the merchant's advertised schema is authoritative.

Bundled global catalog operations — search for discovery, lookup for refreshing saved or bookmarked product/variant IDs (carts, wish lists, deep links), and get_product for full PDP detail — take well-known inputs covered below and in references/CATALOG.md; you don't need to introspect before basic use. Reach for --input-schema when adding extension fields (like, signals, etc.), when live schema differs, or when composing checkout payloads.

> ucp --schema is a different thing — it describes the CLI wrapper itself (args/options like --input, --set, --business). Not the payload schema. Use --input-schema for payload composition.

Positional id vs body input

Ops that act on an existing resource take its id as the first positional argument. The id is not a body field — don't duplicate it in --input/--set.

  • cart get/update/cancel
  • checkout get/update/complete/cancel
  • order get
  • catalog get_product (pass result.products[N].id from a prior search)

All other operations (cart create, checkout create, catalog search, catalog lookup, discover) take no positional; their full payload goes in --input/--set. Cart-to-checkout conversion accepts cart_id in the checkout create body and requires line_items, which can be empty for conversion.

ucp cart update  --business https:// --input '{...}'
ucp catalog get_product                  # global Catalog detail: omit --business
ucp catalog search --set /query='running shoes'

Searching the global catalog

Compose a search with three field groups. For Catalog-specific recipes — search pages, lookup/re-pricing, PDP variant pickers, multimodal like, single-shop shop_ids, auth tiers, and ID pitfalls — read references/CATALOG.md.

  • query — what the buyer is looking for. The literal search term.
  • context — soft signals that inform ranking, localization, and estimates (not exclusions). Includes intent (free-text background, e.g. "looking for a gift under $50" or "durable for outdoor use"), address_country, currency, language, eligibility, etc.
  • filters — hard exclusions. Results that don't satisfy these are dropped (price ranges, availability, shipping constraints, condition).
  • paginationlimit to bound the page size.
ucp catalog search --input '{
  "query": "marathon training shoes",
  "context": {
    "intent": "daily trainer for marathon training",
    "address_country": "US",
    "currency": "USD",
    "language": "en-US"
  },
  "filters": {
    "price":     { "max": 15000 },
    "available": true,
    "ships_to":  { "country": "US" }
  },
  "pagination": { "limit": 10 }
}' \
  --view 'result.products[*].{title: title, seller_domain: variants[0].seller.domain, seller_url: variants[0].seller.url, price_from: price_range.min.amount, currency: price_range.min.currency, variant_id: variants[0].id, pdp: variants[0].url, buy: variants[0].checkout_url, rating: rating.value}'

--view '' projects the response down to the fields you actually need (title/seller/price/routing/handoff URLs in this case) instead of dragging the full variant tree into context. The cta survives the projection, so next-step recommendations remain available. Keep variants[M].id and variants[M].seller.domain in the projection whenever a cart or checkout step might follow. Use --view :compact only when a display-only title/price/variant/buy table is enough; use an inline or @ projection when routing fields must survive. See Working with responses below for the projection pattern across cart, checkout, and order responses.

When the buyer mentioned a brand or store name, read seller identity from variants[*].seller.domain, not the brand in title. The same brand can appear from first-party stores and third-party resellers in the same result set; only seller.domain distinguishes them.

Don't fabricate context fields you don't have — leave them out. For "more like this" or visual similarity, use --input '{"like": ...}' and check --input-schema for the exact like fields supported.

Pagination — vary the query first

catalog search is the only paginated operation. The response carries result.pagination when more pages exist, and the CTA includes the fetch-next command. Pagination gives more of the same ranking. When results miss the buyer's intent, vary the query first — try synonyms, broader/narrower terms, brand names — then paginate only if the new query confirms the result set is what you want. Cursors are opaque and may be invalidated as inventory changes; don't hand-roll cursor calls, follow the CTA.

Looking up a specific product

catalog search is the right tool for browsing. When the buyer narrows to a specific product — picking switch/color/size from a multi-variant matrix, or wanting real-time per-variant pricing/availability — use ucp catalog get_product (id is positional; pass result.products[N].id from a prior global Catalog search, and omit --business unless you intentionally want a merchant-scoped catalog). The response is result.product (singular, not products[]) and contains the full options[] matrix and current variant-level state.

get_product vs lookup: a single pasted link the buyer wants to open (PDP + variant picker) → get_product. A batch of saved IDs the buyer wants to refresh (prices, stock, validity) → lookup.

Working with responses

UCP responses can be rich across every operation — catalog search returns dozens of products with full variant trees, cart can carry itemized totals + fulfillment estimates + messages, checkout carries final totals + full fulfillment options + messages, and order responses carry fulfillment events and adjustments. Across all of them, apply the same tactic: grok the response shape, then project the fields relevant to the current task before reasoning over the result. Loading a 300 KB blob into context just to find five product titles (or five total amounts) wastes most of your budget.

Two equally good options — pick whichever fits the task:

# Built-in alias: :summary resolves to cart.summary.jmespath for cart commands.
ucp cart create --input '...' --view :summary

# Inline JMESPath still works. The expression runs over the whole envelope;
# output replaces the envelope. CTAs survive the projection.
ucp cart create --input '...' \
  --view "result.{id: id, currency: currency, items: length(line_items), total: totals[?type=='total'] | [0].amount, continue_url: continue_url}"

# Or pipe to jq if you have it (full envelope as default JSON output)
ucp cart create --input '...' --format json \
  | jq '.result | {id, currency, items: (.line_items|length), total: (.totals[]? | select(.type=="total") | .amount), continue_url}'

The exact projection depends on what the current task needs — don't paste boilerplate, compose for THIS step. Common shapes by operation:

  • catalog search — see the example under Searching the global catalog above; include variants[M].id in your projection whenever a cart or checkout step might follow.
  • cartresult.{id, currency, line_items, totals, messages, fulfillment, continue_url}; cart totals are estimates when fulfillment destination is involved (totals[?type=='total'] | [0].amount).
  • checkoutresult.{id, status, currency, line_items, totals, messages, fulfillment, continue_url}; checkout is the final/full-fidelity fulfillment option surface. Reach into messages[?severity=='recoverable'] for actionable errors.
  • orderresult.{id, status, fulfillment: fulfillment.{status: status, events: events[*].{type: type, at: at, location: location}}}.

Common JMESPath patterns (filters, sort, multi-select, slicing) are in references/REFERENCE.md. Package-local aliases such as --view :compact and --view :summary resolve from the CLI package's skills/ucp/views directory by operation capability (catalog search --view :summarycatalog.summary.jmespath; cart create --view :summarycart.summary.jmespath). Read the files in views/ as shape references, but compose your own projection for what THIS call needs; use @ for edited/custom views.

Key response fields and conventions

  • result.products[N] — each product carries id, title, description, rating, options[] (variant axes like color/size), price_range ({min, max} across variants — prefer over variants[0].price for buyer-facing display), variants[M].
  • result.products[N].variants[M] — each variant carries id (merchant-specific format; pass verbatim into cart/checkout — don't reconstruct from URLs), title, url (PDP — the canonical browse target), checkout_url (merchant-hosted buy-now), price (object {amount, currency}), availability (object {available, ...} — check .available), seller (object {name, domain, url}domain is the safe key for --business; url is the homepage for buyer-facing display).
  • seller.url is the seller's homepage, NOT a buyer-handoff target. For handoff use variants[M].url (PDP) or variants[M].checkout_url (buy-now).
  • Minor currency units apply to every amount in the response. 15000 = $150.00 USD; 4998 = $49.98 USD. Always check the corresponding currency field before formatting for the buyer.
  • Cart/checkout responses carry pricing in result.totals[] (itemized; one subtotal + one total guaranteed), result.currency (resolved ISO 4217), and per-line result.line_items[N].item.price. Cart fulfillment lines are estimates; checkout fulfillment lines are the final pre-completion numbers. There is no result.cost field.
  • Line identity vs item identityresult.line_items[N].id is the targetable existing line id for updates and fulfillment targeting; result.line_items[N].item.id is the underlying item/variant id. Net-new create lines do not have a line id yet — do not invent one.

To get the most up-to-date price, availability, and merchant-specific cart totals, add the product to a cart.

Fulfillment and line items — quick model

Use this ladder: **context hints ' against the merchant's live --input-schema`. Quote string-valued fields explicitly in JSON so numeric-looking strings (ZIP codes, IDs) stay strings:

ucp cart create --business https:// --input '{
  "line_items": [{"item":{"id":""},"quantity":1}],
  "context":    {"address_country":"US"}
}'

Checkout

checkout create has two modes. If you already built a cart, prefer cart conversion: pass the cart result id as cart_id in the checkout body when checkout create --input-schema advertises it, and include line_items: []. line_items is required but can be empty for cart conversion; the merchant uses the cart contents when cart_id is present. Use real line_items only for buy-now flows where no cart exists. Do not use cart line I

Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet, be the first.

Versions

  • v0.1.0 Imported from the upstream source.