[{"data":1,"prerenderedAt":352},["ShallowReactive",2],{"work-shopagent":3},{"id":4,"title":5,"body":6,"category":314,"challenge":315,"codeSnippet":316,"description":320,"extension":321,"featured":322,"finalScreenshot":323,"gridOrder":324,"isDemo":322,"isDemoURL":39,"liveUrl":324,"meta":325,"mockupImage":326,"navigation":327,"nextProject":324,"order":328,"path":329,"results":324,"schneiderFeatured":327,"schneiderOrder":297,"seo":330,"solution":331,"stem":332,"subtitle":333,"tags":334,"techStack":340,"thumbnail":348,"thumbnailVideo":349,"year":350,"__hash__":351},"works/works/shopagent.md","ShopAgent",{"type":7,"value":8,"toc":296},"minimark",[9,14,18,21,24,29,40,45,74,77,79,83,87,94,98,101,105,112,116,122,124,128,132,172,176,214,216,220],[10,11,13],"h1",{"id":12},"shopagent-ucp-compliant-ai-shopping-assistant","ShopAgent — UCP-Compliant AI Shopping Assistant",[15,16,17],"p",{},"A production-grade agentic commerce application that replaces traditional browse-and-click shopping with natural language commerce. Users describe what they want, and the AI agent discovers products across the entire Shopify ecosystem, compares prices across merchants, manages checkout, and handles payment — all in a single conversational interface.",[15,19,20],{},"This isn't a chatbot bolted onto a storefront. It's a UCP-native agent that implements the full buyer journey: discovery → refinement → checkout → order confirmation.",[22,23],"hr",{},[25,26,28],"h2",{"id":27},"architecture","Architecture",[30,31,36],"pre",{"className":32,"code":34,"language":35},[33],"language-text","┌───────────────────────────────────────────────────────────┐\n│                    Nuxt 3 Frontend                         │\n│   Chat UI  ←→  Product Carousels  ←→  ECP Checkout        │\n│          (SSE streaming + Pinia stores)                    │\n└─────────────────────┬─────────────────────────────────────┘\n                      │ SSE\n┌─────────────────────┴─────────────────────────────────────┐\n│              Nitro API Layer                                │\n│   Agent Orchestrator (Claude API + Tool Definitions)       │\n│   JWT Token Manager  │  Session Store  │  UCP Negotiation  │\n└──────┬────────────────────┬────────────────────┬──────────┘\n       │                    │                    │\n  Catalog MCP         Checkout MCP        Storefront MCP\n  (Global Discovery)  (Per-Merchant)      (Per-Store)\n","text",[37,38,34],"code",{"__ignoreMap":39},"",[41,42,44],"h3",{"id":43},"how-the-agent-works","How the Agent Works",[46,47,48,52,55,62,65,68,71],"ol",{},[49,50,51],"li",{},"User sends a message (\"Find sustainable running shoes under $150\")",[49,53,54],{},"Nitro API passes it to the Agent Orchestrator",[49,56,57,58,61],{},"Claude analyzes intent and calls tools (e.g., ",[37,59,60],{},"search_global_products",")",[49,63,64],{},"Orchestrator executes tool calls against Shopify MCP servers via JSON-RPC 2.0",[49,66,67],{},"Results feed back to Claude, which may call more tools or generate a response",[49,69,70],{},"Text and tool results stream to the frontend via SSE in real time",[49,72,73],{},"Frontend extracts product data into Pinia stores and renders rich product cards",[15,75,76],{},"The agentic loop runs up to 10 tool rounds per request — enough for complex multi-step flows like \"find shoes, compare prices across merchants, then start checkout with the cheapest one.\"",[22,78],{},[25,80,82],{"id":81},"key-engineering-decisions","Key Engineering Decisions",[41,84,86],{"id":85},"full-replacement-checkout-updates","Full-Replacement Checkout Updates",[15,88,89,90,93],{},"Shopify's ",[37,91,92],{},"update_checkout"," is not a PATCH — it's a full replacement. Every call must include ALL fields (line items, buyer info, shipping) or they get dropped. The agent maintains complete checkout state and replays it on every update.",[41,95,97],{"id":96},"multi-merchant-checkout","Multi-Merchant Checkout",[15,99,100],{},"A single search returns products from multiple Shopify stores. Each merchant requires its own checkout session. The agent manages parallel checkout flows, each with independent state machines.",[41,102,104],{"id":103},"embedded-checkout-protocol-ecp","Embedded Checkout Protocol (ECP)",[15,106,107,108,111],{},"When checkout requires payment credentials the agent can't handle (card numbers, 3D Secure), it escalates to a sandboxed iframe with bidirectional JSON-RPC 2.0 communication via ",[37,109,110],{},"postMessage",", delegation handlers for payment instruments and credentials, and auto-response with cached buyer data where possible.",[41,113,115],{"id":114},"streaming-ux","Streaming UX",[15,117,118,119,121],{},"SSE interleaves text chunks and tool execution status. The frontend shows real-time typing with a streaming cursor, human-readable tool names (\"Searching products...\" not ",[37,120,60],{},"), and inline product carousels that appear as results arrive.",[22,123],{},[25,125,127],{"id":126},"what-i-built","What I Built",[41,129,131],{"id":130},"server-layer-16-files","Server Layer (16 files)",[133,134,135,142,148,154,160,166],"ul",{},[49,136,137,141],{},[138,139,140],"strong",{},"Agent orchestrator"," — Agentic loop managing Claude API ↔ tool execution ↔ response streaming",[49,143,144,147],{},[138,145,146],{},"3 MCP wrappers"," — Type-safe clients for Catalog, Checkout, and Storefront servers",[49,149,150,153],{},[138,151,152],{},"JSON-RPC 2.0 client"," — Exponential backoff retries, transport/RPC/business error classification",[49,155,156,159],{},[138,157,158],{},"JWT token manager"," — Auto-refresh with 5-minute buffer before 60-min expiry",[49,161,162,165],{},[138,163,164],{},"11 tool definitions"," across 3 MCP servers matching Shopify's API schemas",[49,167,168,171],{},[138,169,170],{},"UCP profile + negotiation"," — Capability declaration and intersection computation",[41,173,175],{"id":174},"frontend-layer-15-components-5-composables-2-stores","Frontend Layer (15 components + 5 composables + 2 stores)",[133,177,178,184,190,196,202,208],{},[49,179,180,183],{},[138,181,182],{},"Chat interface"," — Message list, streaming input, typing indicator",[49,185,186,189],{},[138,187,188],{},"Product carousels"," — Horizontal scroll cards with images, pricing, merchant info",[49,191,192,195],{},[138,193,194],{},"Cart sidebar"," — Per-shop grouping, quantity controls, slide-in animation",[49,197,198,201],{},[138,199,200],{},"Checkout status"," — Step-based progress with status colors and recovery hints",[49,203,204,207],{},[138,205,206],{},"ECP iframe"," — Sandboxed embedded checkout with delegation bridge",[49,209,210,213],{},[138,211,212],{},"Demo mode"," — 3 pre-configured scenarios that run without API keys",[22,215],{},[25,217,219],{"id":218},"tech-stack","Tech Stack",[221,222,223,236],"table",{},[224,225,226],"thead",{},[227,228,229,233],"tr",{},[230,231,232],"th",{},"Layer",[230,234,235],{},"Technology",[237,238,239,248,256,264,272,280,288],"tbody",{},[227,240,241,245],{},[242,243,244],"td",{},"Frontend",[242,246,247],{},"Nuxt 3, Vue 3 Composition API, Tailwind CSS v4",[227,249,250,253],{},[242,251,252],{},"Agent",[242,254,255],{},"Claude API with custom tool definitions",[227,257,258,261],{},[242,259,260],{},"Protocol",[242,262,263],{},"JSON-RPC 2.0 over HTTPS to Shopify MCP servers",[227,265,266,269],{},[242,267,268],{},"State",[242,270,271],{},"Pinia stores (conversation, cart, checkouts, orders)",[227,273,274,277],{},[242,275,276],{},"Auth",[242,278,279],{},"JWT tokens (OAuth client credentials, 60-min TTL, auto-refresh)",[227,281,282,285],{},[242,283,284],{},"Streaming",[242,286,287],{},"Server-Sent Events from Nitro to frontend",[227,289,290,293],{},[242,291,292],{},"Language",[242,294,295],{},"TypeScript (strict mode) throughout",{"title":39,"searchDepth":297,"depth":297,"links":298},2,[299,303,309,313],{"id":27,"depth":297,"text":28,"children":300},[301],{"id":43,"depth":302,"text":44},3,{"id":81,"depth":297,"text":82,"children":304},[305,306,307,308],{"id":85,"depth":302,"text":86},{"id":96,"depth":302,"text":97},{"id":103,"depth":302,"text":104},{"id":114,"depth":302,"text":115},{"id":126,"depth":297,"text":127,"children":310},[311,312],{"id":130,"depth":302,"text":131},{"id":174,"depth":302,"text":175},{"id":218,"depth":297,"text":219},"Agentic Commerce","Shopify's Universal Commerce Protocol launched with backing from Walmart, Target, Visa, Mastercard, and Stripe — yet almost no independent developers have built production-grade UCP agents. The protocol is complex, the reference implementations are minimal, and building a full buyer journey requires coordinating three MCP servers, multi-merchant checkout state, and payment escalation.",{"language":317,"filename":318,"code":319},"typescript","server/api/agent/orchestrator.ts","async function runAgentLoop(\n  messages: Message[],\n  tools: ToolDefinition[]\n): Promise\u003CStreamableResponse> {\n  let toolRound = 0\n  const MAX_ROUNDS = 10\n\n  while (toolRound \u003C MAX_ROUNDS) {\n    const response = await anthropic.messages.create({\n      model: 'claude-sonnet-4-20250514',\n      messages,\n      tools,\n      stream: true,\n    })\n\n    const toolCalls = extractToolCalls(response)\n    if (toolCalls.length === 0) break\n\n    const results = await Promise.all(\n      toolCalls.map(tc => executeMcpTool(tc))\n    )\n    messages.push(...formatToolResults(results))\n    toolRound++\n  }\n\n  return streamResponse(messages)\n}\n","Full-stack agentic commerce app — conversational product discovery across the entire Shopify ecosystem, multi-merchant checkout, Embedded Checkout Protocol, and streaming UI.","md",false,"/images/projects/shopagent-final.jpg",null,{},"/images/projects/shopagent-mockup.jpg",true,10,"/works/shopagent",{"title":5,"description":320},"A UCP-native agent implementing the complete buyer journey: discovery, refinement, checkout, and order confirmation. Three MCP server integrations (Catalog, Checkout, Storefront), agentic orchestration via Claude API with up to 10 tool rounds per request, full-replacement checkout state management, Embedded Checkout Protocol for payment escalation, and a streaming Nuxt 3 frontend with real-time product carousels.","works/shopagent","UCP Shopping Assistant",[335,336,337,338,339,314],"Shopify UCP","Catalog MCP","Checkout MCP","Nuxt 3","Claude API",[338,341,342,339,343,337,344,345,346,347],"Vue 3","TypeScript","Shopify Catalog MCP","Storefront MCP","Pinia","Tailwind CSS v4","SSE","/images/projects/shopify-agent.jpg","/videos/shopagent.mp4","2026","wLnkOmmdpjdsRwPLZ5JvcM8j73Qh3T8CUeSl0sYmWW4",1773700381157]