[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"project-81601":3},{"id":4,"name":5,"fullName":6,"owner":7,"repo":5,"description":8,"homepage":9,"htmlUrl":10,"language":11,"languages":10,"totalLinesOfCode":10,"stars":12,"forks":13,"watchers":14,"openIssues":15,"contributorsCount":16,"subscribersCount":16,"size":16,"stars1d":17,"stars7d":18,"stars30d":19,"stars90d":16,"forks30d":16,"starsTrendScore":20,"compositeScore":21,"rankGlobal":10,"rankLanguage":10,"license":22,"archived":23,"fork":23,"defaultBranch":24,"hasWiki":23,"hasPages":23,"topics":25,"createdAt":10,"pushedAt":10,"updatedAt":26,"readmeContent":27,"aiSummary":28,"trendingCount":16,"starSnapshotCount":16,"syncStatus":17,"lastSyncTime":29,"discoverSource":30},81601,"ucp-cli","Shopify\u002Fucp-cli","Shopify","A shopping skill for AI agents, powered by the Universal Commerce Protocol.","https:\u002F\u002Fshopify.dev\u002Fagents",null,"TypeScript",28,4,23,1,0,2,3,5,6,2.1,"MIT License",false,"main",[],"2026-06-12 02:04:17","# `@shopify\u002Fucp-cli`\n\n**A shopping skill for AI agents, powered by the [Universal Commerce Protocol](https:\u002F\u002Fgithub.com\u002FUniversal-Commerce-Protocol\u002Fucp).**\n\n- **Search products across millions of merchants** via a unified global catalog\n- **Build carts and complete checkouts** against any UCP-enabled merchant\n- **Hand off gracefully** when escalation is requested\n- **Track orders** after purchase\n\nDesigned agent-first. Structured JSON I\u002FO on every command. Schema introspection on every operation (`--input-schema`), so the agent composes payloads from the merchant's advertised schemas instead of stale docs. Built-in escalation hooks, response shaping, and first-class knowledge of UCP best practices for presentation requirements, error handling, and more. Works with any agent that supports the [skills format](https:\u002F\u002Fagentskills.io\u002F).\n\n## 60-second tour for carbon life forms\n\n```sh\n$> npm install -g @shopify\u002Fucp-cli\n$> ucp skills add\n$> ucp profile init --name shopper\n```\n### 1. Find products\n\n```sh\nucp catalog search \\\n  --set \u002Fquery='keychron b1 pro' \\\n  --set \u002Fcontext\u002Fintent='looking for great mechanical keyboard' \\\n  --set \u002Fcontext\u002Faddress_country=US \\\n  --view :compact \\\n  --format md\n```\n\nThe query resolves against global catalog, searching across millions of merchants. `--view` projects the response (a [JMESPath](https:\u002F\u002Fjmespath.org) expression — inline, `@\u003Cfile>`, or package-local `:\u003Calias>`); `--format md` renders the projection as a table:\n\n| title | price | currency | variant | buy |\n|---|---|---|---|---|\n| Keychron B1 Pro Ultra-Slim Wireless Keyboard | 3999 | USD | gid:\u002F\u002Fshopify\u002FProductVariant\u002F41293818167385 | https:\u002F\u002Fwww.keychron.com\u002Fcart\u002F41293818167385:1 |\n| Keychron B1 Pro 75% Wireless Low Profile Keyboard | 3700 | USD | gid:\u002F\u002Fshopify\u002FProductVariant\u002F49158410436908 | https:\u002F\u002Fmechanicalkeyboards.com\u002Fcart\u002F49158410436908:1 |\n| KEYCHRON B1 PRO WIRELESS KEYBOARD | 4600 | USD | gid:\u002F\u002Fshopify\u002FProductVariant\u002F50230394749266 | https:\u002F\u002Feloquentclicks.com\u002Fcart\u002F50230394749266:1 |\n\nNote: passing `--business \u003Curl>` scopes the search to that merchant — the CLI discovers the merchant's search endpoint and queries it directly. Omit `--business` to search the bundled global catalog (the default).\n\n### 2. Add it to a cart at the chosen merchant\n\n```sh\nucp cart create --business https:\u002F\u002Fkeytron.myshopify.com \\\n  --set \u002Fline_items\u002F0\u002Fitem\u002Fid='gid:\u002F\u002Fshopify\u002FProductVariant\u002F41293818167385' \\\n  --set \u002Fline_items\u002F0\u002Fquantity=1 \\\n  --set \u002Fcontext\u002Faddress_country=US \\\n  --view 'result.{id: id, items: length(line_items), currency: currency, continue_url: continue_url}'\n```\n\nThe merchant returns a cart with confirmed pricing and `continue_url` that the buyer can optionally open to checkout. Want to add more items? Save and pass the returned `cart.id` to update the cart. For existing lines, `result.line_items[N].id` is the targetable line id; `result.line_items[N].item.id` is the underlying item\u002Fvariant id. Net-new create lines do not have a line id yet — do not invent one.\n\nNeed a shipping-cost preview before checkout? Inspect `ucp cart update --input-schema`; if the merchant accepts fulfillment destinations on cart update, send the buyer destination there to get merchant-provided estimates. Use checkout for the complete shipping\u002Fpickup option map and final selectable options.\n\n### 3. Convert to checkout, configure handoff, complete\nSome checkouts require additional buyer input or review that the agent can't negotiate on the buyer's behalf. When the merchant returns an escalation status with a continue URL, configure a custom hook and the CLI will call it to handle the handoff. \n\n```sh\nexport UCP_ON_ESCALATION='jq -r .url | xargs open'   # macOS; xdg-open on Linux\n\n# Convert the cart from step 2 into a checkout. For buy-now flows (no cart), pass line_items directly.\nucp checkout create --business https:\u002F\u002Fkeytron.myshopify.com \\\n  --input '{\"cart_id\":\"\u003Ccart_id from step 2>\",\"line_items\":[]}' \\\n  --view 'result.{id: id, status: status}'\n\n# … then `ucp checkout update \u003Cid>` for fulfillment address\u002Fselection. Cart can\n# estimate shipping, but checkout returns the full-fidelity option map and final\n# selectable shipping\u002Fpickup choices. Then `ucp checkout complete \u003Cid>`.\n```\n\nMulti-merchant flows are negotiated by passing relevant `--business` parameter for each call. \n\n_NOTE: Shopify-powered merchants support unauthenticated catalog access. Checkout requires a Catalog JWT — sign in to the Shopify Developer Dashboard to obtain one._\n\n---\n\n## Use with agents\n\nAfter `ucp skills add`, your agent has the bundled `SKILL.md` — it teaches the agent how to find products and walk the buyer through the purchase journey against any UCP merchant. \n\n\n| Buyer asks... | Agent runs... |\n|---|---|\n| \"Find me wireless headphones under $200\" | `ucp catalog search` against the bundled global catalog (no merchant pinning needed) |\n| \"Buy this from store.example.com\" | `ucp discover --business \u003Curl>` to confirm UCP support, then `cart create` \u002F `checkout create` scoped to that merchant |\n| \"Where's my order?\" | `ucp order get \u003Corder_id> --business \u003Curl>` |\n| Anything mid-flow that the merchant requires the buyer to confirm | The configured escalation hook opens the buyer's browser to `result.continue_url`; the agent waits for the buyer to confirm, then resumes |\n\nThe skill packages the agent-facing operating model — when to search vs discover, how to compose payloads from the merchant's live schema, how to render totals correctly, how to surface required disclosures, when and how to hand off — in one curated [`skills\u002Fucp\u002FSKILL.md`](skills\u002Fucp\u002FSKILL.md) plus on-demand reference files.\n\n\n## How it works\n\nA **business** is a URL — `https:\u002F\u002Fshop.example.com`. The CLI fetches the business's UCP profile (cached on disk per spec TTL), negotiates a compatible protocol version + transport, and dispatches operations against its endpoint. UCP CLI abstracts transport, service + capability negotiation, ..., and error handling.\n\nTwo scopes for picking which business an operation targets:\n\n- **Global catalog (no `--business`)** — for product discovery across thousands of merchants. Each result names its merchant via `seller.domain`.\n- **Per-merchant (`--business \u003Curl>`)** — for cart, checkout, order, or catalog operations scoped to a single merchant. \n\n**Live introspection so the agent never guesses.** Both `discover` and `--input-schema` make a real network call to the merchant; they're not static doc lookups. The schema you get back is whatever the merchant currently advertises — including extensions they've added since you last shopped there. Merchants stay in authoritative control of their own schemas; they can evolve, deprecate, or extend without coordinated releases against the CLI or the agent. Capability negotiation is real: the agent and merchant agree on what to use based on what's actually offered right now.\n\n```sh\nucp discover --business https:\u002F\u002F\u003Cseller-domain>                         # what operations are offered\nucp catalog search --input-schema --business https:\u002F\u002F\u003Cseller-domain>    # exact shape this operation accepts\nucp cart update --input-schema --business https:\u002F\u002F\u003Cseller-domain>       # cart-stage shipping estimates, if supported\nucp checkout update --input-schema --business https:\u002F\u002F\u003Cseller-domain>   # full fulfillment option map\u002Ffinal fields\n```\n\n**Every response carries a `cta`.** The CLI is context-aware — it tracks where you are in the flow and surfaces the next-best step(s) as structured recommendations the agent should consider. Successful responses point forward (cart created → here are the checkout \u002F refine \u002F search-more commands); error responses point at recovery (schema validation failed → here's the `--input-schema` command to introspect first). The agent doesn't have to memorize the operating model; the CLI threads it through.\n\n```sh\n$ ucp cart create --business https:\u002F\u002Fshop.example.com \\\n    --set \u002Fline_items\u002F0\u002Fitem\u002Fid='gid:\u002F\u002Fshopify\u002FProductVariant\u002F123' \\\n    --set \u002Fline_items\u002F0\u002Fquantity=1 \\\n    --format json | jq '.cta'\n{\n  \"description\": \"Cart saved. Ready to buy? Create a checkout from this cart by passing cart_id and line_items: [] in --input. Need shipping cost before checkout? Cart can provide merchant estimates when its schema accepts fulfillment destinations; use checkout for the complete option map.\",\n  \"commands\": [\n    { \"command\": \"ucp checkout create --business \u003Cbusiness> --input '{\\\"cart_id\\\":\\\"\u003Ccart_id>\\\",\\\"line_items\\\":[]}'\", \"description\": \"convert this cart to a checkout\" },\n    { \"command\": \"ucp cart update --input-schema --business \u003Cbusiness>\", \"description\": \"inspect cart schema before requesting shipping estimates\" },\n    { \"command\": \"ucp cart update \u003Ccart_id> --business \u003Cbusiness> --input '...'\", \"description\": \"request cart-stage shipping estimates with fulfillment destinations\" },\n    { \"command\": \"ucp catalog search ...\", \"description\": \"find more items — add them to this cart before proceeding\" }\n  ]\n}\n```\n\n## Beyond the basics\n\n### Composing operation calls\n\nThree input surfaces — pick the right one for what you're providing:\n\n- **Positional `\u003Cid>`** — for operations that address an existing resource: `cart get\u002Fupdate\u002Fcancel`, `checkout get\u002Fupdate\u002Fcomplete\u002Fcancel`, `order get`, `catalog get_product`. Pass the id as the first argument; it's not a body field, so don't duplicate it in `--input`\u002F`--set`. Creating\u002Fsearching operations (`cart create`, `checkout create`, `catalog search`, `catalog lookup`, `discover`) take no positional. Cart-to-checkout conversion is a normal `checkout create` body: pass `cart_id` in `--input` when the merchant's input schema advertises it.\n- **`--input '\u003Cjson>'`** — the operation body as a single JSON object. Also accepts `@path` (load from file) or `-` (read from stdin).\n- **`--set \u003Cpath>=\u003Cvalue>`** — overlay one body field at a [JSON Pointer (RFC 6901)](https:\u002F\u002Fdatatracker.ietf.org\u002Fdoc\u002Fhtml\u002Frfc6901) path. Numeric segments auto-create arrays (the cart example above); `-` as the final segment appends (`--set '\u002Fline_items\u002F-=\u003Cjson>'`). Repeatable. `--set-string` forces string interpretation for numeric-looking values like ZIP codes.\n\n`--input` and `--set` mix freely: `--input '{...base...}' --set \u002Fcontext\u002Faddress_country=US`. See [`skills\u002Fucp\u002Freferences\u002FREFERENCE.md`](skills\u002Fucp\u002Freferences\u002FREFERENCE.md) for the full `--set` syntax (escape rules, array indices, append, etc.). \n\n### Project responses before reasoning over them\n\nUCP responses carry full product and negotiation details — variant trees, options, pricing, fulfillment shape, messages. Tailor and filter the response before passing it to your output formatter (or to an agent reasoning over it). One source response, many projections, no re-fetch required.\n\n**Built-in: `--view \u003Cexpr|@file|:alias>`.** A [JMESPath](https:\u002F\u002Fjmespath.org) projection. The expression runs over the whole response envelope (`business`, `endpoint`, `transport`, `ucp`, `result`) and its output **replaces** the envelope, so the view has full control over the rendered shape. The `cta` survives the projection. `:\u003Calias>` loads from the CLI package's `skills\u002Fucp\u002Fviews` directory for the current operation capability (`catalog search --view :summary` → `catalog.summary.jmespath`); `@file` loads a custom or edited view. Composes with `--format` (project first, render second), so `--view ... --format md` is one command from raw payload to a markdown table.\n\n```sh\n# Inline expression — reach into `result` from envelope root\nucp catalog search --set \u002Fquery='running shoes' \\\n  --view 'result.products[*].{title: title, seller_domain: variants[0].seller.domain, seller_url: variants[0].seller.url, price: price_range.min.amount}'\n\n# Package-local view alias — resolves inside the CLI package's skills\u002Fucp\u002Fviews;\n# --format md gives a table\nucp catalog search --set \u002Fquery='running shoes' \\\n  --view :summary \\\n  --format md\n```\n\n**JMESPath cheatsheet** for the patterns you'll reach for most (root is the envelope; reach into `result.\u003C...>` for the operation payload):\n\n| Pattern | Does |\n|---|---|\n| `field` \u002F `a.b.c` | Pluck a field \u002F nested path (`result.id`, `ucp.version`) |\n| `[*]` \u002F `a[*].b` | Project over every element of an array (`result.products[*].title`) |\n| `` [?expr] `` | Filter — numeric literals need backticks (`` result.products[?price_range.min.amount\u003C`5000`] ``) |\n| `[N]` \u002F `[N:M]` | Index \u002F slice (`variants[0]`, `result.products[:5]`) |\n| `sort_by(@, &expr)` | Sort by an expression (`sort_by(result.products, &price_range.min.amount)`) |\n| `length(@)` | Count (`length(result.products)`) |\n| `{a: x, b: y}` | Build a multi-key object (the projections above) |\n\nFull spec at [jmespath.org](https:\u002F\u002Fjmespath.org). `jq` and other tools (Python, Node, etc.) still work fine if you prefer — pipe the default JSON output into them. `--filter-output` remains for path-narrowing one field without an expression engine.\n\n### Escalation hook recipes\n\nFires when checkout `result.status === \"requires_escalation\"`. Receives a compact JSON payload (`status`, `url`, `reason`, `business`, `operation`) on stdin. Auth-class errors (`AUTH_REQUIRED`, `INSUFFICIENT_PERMISSIONS`) do **not** fire the hook — they return structured error CTAs so the agent can hand off using the best URL it already has.\n\nConfigure one (first match wins):\n\n- **Per-call flag** — `ucp \u003Cop> --on-escalation '\u003Ccmd>'`\n- **Env var** — `export UCP_ON_ESCALATION='\u003Ccmd>'` (most common)\n- **Persistent config** — `~\u002F.ucp\u002Fconfig.yaml`: `escalation.command: '\u003Ccmd>'`\n\n`\u003Ccmd>` runs through `\u002Fbin\u002Fsh -c` on POSIX and `cmd.exe \u002Fd \u002Fs \u002Fc` on Windows. To run an existing script, point at it directly: `'\u002Fpath\u002Fto\u002Fescalation.sh'` (POSIX) or `'powershell -NoProfile -File C:\\path\\escalation.ps1'` (Windows).\n\nOne-shot, interactive (browser open):\n\n```sh\nucp checkout complete \u003Cid> --business https:\u002F\u002F\u003Cseller-domain> \\\n  --on-escalation 'jq -r .url | xargs open'\n```\n\nSticky for the rest of your session (or for an agent that calls `ucp` many times):\n\n```sh\n# Browser open\nexport UCP_ON_ESCALATION='jq -r .url | xargs open'        # macOS\nexport UCP_ON_ESCALATION='jq -r .url | xargs xdg-open'    # Linux\n\n# Generic webhook (Slack, Discord, internal alerting — pipe JSON to your endpoint)\nexport UCP_ON_ESCALATION='curl -sX POST -H \"Content-Type: application\u002Fjson\" --data @- \"$WEBHOOK_URL\"'\n\n# Browser open + macOS notification\nexport UCP_ON_ESCALATION='jq -r .url | tee >(xargs open) | xargs -I{} osascript -e \"display notification \\\"Confirm checkout: {}\\\"\"'\n```\n\n### Preview before issuing mutations\n\n```sh\nucp cart update \u003Cid> --business https:\u002F\u002F\u003Cseller-domain> \\\n  --input '{\"line_items\":[{\"id\":\"\u003Cline_item_id>\",\"item\":{\"id\":\"\u003Cvariant_id>\"},\"quantity\":2}]}' \\\n  --dry-run\n```\n\nBuilds and validates the request, prints the exact payload that would hit the wire (including auto-injected `meta.idempotency-key` and `meta.ucp-agent`), skips the network call. Cart and checkout updates are full-replace: carry forward request-shaped line items, using `line_items[].id` only for existing lines and `line_items[].item.id` for the underlying item\u002Fvariant. Useful for debugging payloads or confirming a mutation before issuing it.\n\n### Custom request headers (auth, tenancy, tracing)\n\nUCP requests attach a built-in `User-Agent: @shopify\u002Fucp-cli\u002F\u003Cversion>`. Override or extend with two user sources, merged with the built-in by priority (lowest to highest):\n\n0. CLI built-in `User-Agent`\n1. `~\u002F.ucp\u002Fprofiles\u002F\u003Cname>\u002Fheaders.json` `default` block — apply to every request\n2. `~\u002F.ucp\u002Fprofiles\u002F\u003Cname>\u002Fheaders.json` `businesses[\u003Corigin>]` block — per-origin add\u002Foverride\n3. `--header 'Name: Value'` (repeatable) — per-call\n\nHigher source wins per header name (case-insensitive); non-conflicting headers from every source ship. Empty values unset for that scope. Framing headers the dispatcher owns (`Content-Type`, `Accept`, `Host`, `Connection`, hop-by-hop, `MCP-Protocol-Version`) are silently dropped from all user sources. Sensitive header values (`Authorization`, `Cookie`, and any name ending in `-Token`, `-Key`, `-Secret`, `-Password`) are redacted in verbose traces (`UCP_VERBOSE=1`).\n\nPersistent setup, modeled on git's `[http]` \u002F `[http \"\u003CURL>\"]`:\n\n```json\n{\n  \"default\": {\n    \"Trace-Id\": \"my-agent-${HOSTNAME}\"\n  },\n  \"businesses\": {\n    \"https:\u002F\u002Fshop.example.com\": {\n      \"Authorization\": \"Bearer ${EXAMPLE_TOKEN}\"\n    }\n  }\n}\n```\n\nValues support `${ENV_VAR}` interpolation so the file stays free of secrets.\n\nPer-call usage:\n\n```sh\n# Bearer auth (covers the most common case in one keystroke)\nucp catalog search --header \"Authorization: Bearer $TOKEN\" --set \u002Fquery='surf boards'\n\n# Multiple headers (repeat the flag)\nucp catalog search --header \"Authorization: Bearer $TOKEN\" --header 'Trace-Id: req-abc'\n```\n\nThere is no `--auth-bearer` flag and no `UCP_AUTH_BEARER` env var. `--header` is the only knob; bearer auth is just one shape it can carry. This keeps the CLI surface from growing every time a merchant picks a different auth header.\n\n### Environment variables\n\n| Variable | Effect |\n|---|---|\n| `UCP_BUSINESS` | Default merchant URL when `--business` is omitted |\n| `UCP_PROFILE` | Override which local profile is active |\n| `UCP_ON_ESCALATION` | Shell command for the escalation hook (JSON payload on stdin) |\n| `UCP_HOME` | Override the local state directory (default `~\u002F.ucp`) |\n| `UCP_VERBOSE` | Set `1`\u002F`true` to print trace lines to stderr |\n\n\n## Development\n\n```sh\npnpm install       # install deps + activate husky hooks\npnpm build         # bundle to dist\u002F\npnpm test          # unit tests\npnpm test:full     # unit + integration tests (builds first)\npnpm lint          # biome check\npnpm typecheck     # tsc --noEmit\n```\n\nSymlink globally for active dev:\n\n```sh\npnpm build && pnpm link --global\n# Now `ucp` everywhere points at this repo's dist\u002Fbin.js. Re-run pnpm build\n# after changes; the symlink stays valid.\n```\n\n### Debug tracing\n\n`--verbose` (or `UCP_VERBOSE=1`) prints discover\u002Fcache\u002Ftransport trace lines to stderr. Useful when an operation silently no-ops, a cache hit looks stale, or the request that hit the wire doesn't match what you expected. The flag is muted under `--mcp` (stdio JSON-RPC has no human reader and trace lines would confuse log scrapers).\n\nNot listed in `ucp --help`'s Global Options because incur 0.4.5 hard-codes that block with no extension hook — the flag is intercepted in the launcher before incur sees argv. Until upstream exposes a registration API, this is the canonical doc for it.\n","Shopify\u002Fucp-cli 是一个基于通用商务协议（UCP）为AI代理提供的购物技能工具。它允许用户通过统一的全球目录搜索数百万商家的产品，构建购物车并完成结账，并且能够在需要时优雅地进行升级处理以及跟踪购买后的订单。该项目使用TypeScript编写，支持结构化的JSON输入输出和模式自省，确保与任何支持skills格式的AI代理兼容。适用于需要集成智能购物助手功能的场景，如在线客服、虚拟购物助理等，能够显著提升用户体验和操作效率。","2026-06-11 04:05:39","CREATED_QUERY"]