Quickstart — Commerce Shopping Guide (电商导购样板)
Embed a personal shopping assistant that actually remembers each customer — sizes, budget, brand tastes, past purchases — and carries that memory across every visit. Same platform loop as the romance companion quickstart; this page covers only what differs.
1. Create the project
Dashboard → 新建项目 → template 电商导购, or:
curl -X POST https://pouchy.ai/v1/projects \
-H "Authorization: Bearer <FIREBASE_ID_TOKEN>" \
-H "Content-Type: application/json" \
-d '{ "name": "Shop guide", "template": "ecommerce", "createKey": true }'
The template seeds two agents:
- 小满 (
shopperarchetype) — the buyer-facing guide. Tuned for honest, 低压 guidance: it clarifies budget/scenario first, searches the store before it names anything, recommends 2-3 tiered options, points out mismatches, and never invents prices or stock. Cart and order actions are prepared for the shopper to confirm — it never says an order has been placed. - 方晴 (
merchantarchetype) — the operator-facing back office. Reads the store's own numbers (sales, stock, margins, pending changes) before it says anything, turns a request into ONE staged change with before and after, names the store's guardrails when a request exceeds them, and opens the day with a short briefing. See §6 for what it needs from your backend.
Both personas are ordinary editable templates; the method they carry (search → detail → present; read → stage → approve) is prompt text, so you can tune it.
Each of them also arrives with a golden eval suite (agent → 评测): eight cases per persona covering the behaviours that matter for a store — an instruction hidden inside a pasted product page must not become a cart write, "order it for me" must never be answered with "placed", an approval typed into the merchant's chat applies nothing, a move past a stated cap is refused with an in-cap figure. Run them after every persona edit; on an agent whose suite is empty, 「载入示例用例」 offers the same cases again.
2. Session per customer
Mint sessions exactly as in the romance quickstart, with your customer
id as external_user_id. A returning customer gets the same instance —
小满 already knows their size and what they bought last month.
3. Ground it in YOUR catalog (tool calls)
Declare tools when connecting; the agent calls them instead of guessing inventory:
const companion = createCompanion({
baseUrl: 'https://pouchy.ai',
token: session_token,
tools: [{
name: 'search_products',
description: 'Search the live catalog. Returns items with price and stock.',
parameters: {
type: 'object',
properties: {
query: { type: 'string' },
budget: { type: 'number', description: 'max price, CNY' }
},
required: ['query']
}
}]
});
companion.onToolCall(async ({ id, name, argsJson }) => {
if (name === 'search_products') {
const { query, budget } = argsJson as { query: string; budget?: number }; // SDK 已替你 JSON.parse
const items = await myCatalogSearch(query, budget);
await companion.sendToolResult(id, { ok: true, result: { items } });
}
});
Push live page context so recommendations track what the customer is looking at:
companion.sendWorldState({
type: 'shop.viewing',
data: { sku: 'A-1024', title: '羊绒围巾', price: 429 },
retained: true
});
3b. Or connect your storefront's own MCP server (no code)
§3 assumes you have a backend and will implement myCatalogSearch yourself. If
you sell on a hosted platform you may not need to: most storefront platforms now
publish an MCP server for their own catalog, and Pouchy can call it as a
skill — no tool declarations, no onToolCall, no backend.
In the dashboard: agent → 技能 → connect an MCP server. The field carries
presets for the shapes we know; replace {store} with your own store host.
| Platform | Endpoint shape | Status |
|---|---|---|
| Shopify | https://{store}/api/mcp |
untested by Pouchy |
| WooCommerce | https://{store}/wp-json/wp/v2/wpmcp/streamable |
untested by Pouchy |
| Wix | https://{store}/_functions/mcp |
untested by Pouchy |
| Square Online | https://{store}/mcp |
untested by Pouchy |
The roster lives in src/lib/storefront/platforms.ts and is the single source
for three surfaces: these endpoint shapes, the widget-install locations on the
渠道 page, and the storefront chips on the marketing site. A platform without an
mcp field is not a gap waiting for a guessed URL — it means that vendor
publishes no MCP server we know of, and the widget is the whole integration.
The other half: the widget
The conversation itself does not need any of the above. Every platform in the
roster — including the ones with no MCP server — takes the widget, because that
is the web channel: your page POSTs {visitorId, text} to a signed inbound URL
and reads the reply off the response. Create it under 渠道 → 新建渠道 → web;
that form now lists where the snippet goes in each platform's own console
(Shopify: Online Store → Themes → Edit code; Squarespace: Settings → Advanced →
Code Injection, which needs a paid plan; and so on).
"Untested by Pouchy" means exactly that — the shapes come from each vendor's
own documentation, and nothing in this repo has driven them. The Connect button
is the test: it runs a real tools/list against the URL and shows you what came
back, so a wrong shape fails immediately and visibly rather than at a customer's
first question. When a shape is confirmed against a live store the preset flips
to a verified badge in the same change that records the run.
Shopify is the one worth trying first: its storefront server is documented as live on every store and, unusually, as needing no credential for catalog and cart calls. Serve it from the storefront host, so a store on a custom domain works by pasting that domain.
Two things to do after connecting:
- Grant the read-only tools. A custom skill on a platform instance is
confirm-gated, and a synthetic instance has no human to approve a card — so
the call would dead-end. In 免确认工具, tick only the read tools (Shopify:
search_catalog,get_product). Leave anything that mutates a cart or places an order gated. - Check the playbook. An MCP skill installs with no body —
tools/listgives the agent callable names and nothing about the order they go in — so connecting a shape from the table above now seeds a playbook: the flow (search → product detail → present, cart last and only with the shopper's confirmation), the grounding rules, and the instruction to read the server's real tool list before its own names. It rides to every instance as the skill'sinstructionsdoc, which the agent is already told to read before its first call. Edit it under agent → 技能 → 运行手册; the chip on the row says whether the stored text is the shipped default or yours. Write it in English — it goes to the model, not to your customers.
The twelve platforms in the roster with no MCP server take the same
treatment. Their catalog comes in through an OpenAPI import or a
hand-written skill.md instead (agent → 技能 → 自装技能), and an imported
spec ships endpoint descriptions with no flow — the same gap in a different
shape. The 运行手册 button is on every installed skill, whatever its kind, and
what you write there becomes that skill's instructions doc; anything the
manifest itself said moves to skill-body rather than being dropped. Only the
seeding differs: the four MCP shapes above arrive with a flow already written,
everyone else writes theirs once.
Use §3 instead when your catalog is not on a hosted platform, when you need pricing logic the storefront API does not expose, or when you want the agent to see inventory the public storefront does not.
4. Instant UI for product cards
With the ui.render scope (and genui enabled on the agent), 小满 renders
its shortlist as a panel instead of a wall of text. The persona states the
shape, so your renderer can rely on it:
- Shortlist (3–5 options) — one
Cardper product: the title is the product name; inside, anImagewhen the result carried an https image, oneTextline "price · key spec", and oneTextline with the ONE reason it meets what the shopper said they need. The recommended option comes first; at most four cards when they carry images (the panel has a 20-node budget). - Comparison (2–4 finalists) — one
Tablewhose columns are the dimensions the shopper raised and whose rows are the products, followed by oneTextnaming the pick and why. - Nothing appears in a card that was not in a tool result — values come from your catalog's own response, never from the model's memory of a brand.
What a shortlist panel looks like on the wire (render_interface args):
{
"title": "羊绒围巾 · 3 个选项",
"nodes": [
{ "type": "Card", "title": "经典素色羊绒围巾", "children": [
{ "type": "Image", "src": "https://cdn.example.com/a-1024.jpg", "alt": "经典素色羊绒围巾" },
{ "type": "Text", "text": "¥429 · 100% 羊绒 · 180×30cm" },
{ "type": "Text", "text": "预算内最保暖的一条,你说的通勤场景正合适" }
]},
{ "type": "Card", "title": "格纹羊绒混纺围巾", "children": [
{ "type": "Text", "text": "¥299 · 70% 羊绒 · 200×35cm" },
{ "type": "Text", "text": "更便宜,但混纺没有纯羊绒软" }
]}
]
}
Atom reference: companion-instant-ui.md.
5. Notes for production
- Keep one agent per storefront tone; A/B different personas as separate agents in the same project (each has its own id and stats).
- Draft status lets you tune a new persona with a test key while the published one serves traffic.
- Wallet-based in-chat payment is part of the platform's wallet
capability — see
companion-capabilities.md. Note that placing an order is NOT something the seeded personas do on their own: a cart or order write is a confirm-gated action the shopper approves.
6. The merchant agent (商家运营) — what it needs from your backend
方晴 is the back-office half. It has no tools of its own; it drives whatever you declare through the data plane (Quickstart: Agent Data Plane) or a connected store skill. The design it ports is the staged change model: the agent prepares a change, a human applies it, and the guardrails run on your side at both moments.
Views (read_data) — the numbers it reads before it says anything:
| View | Fields (example) | Filters |
|---|---|---|
PricingContext |
listing_id, price, cost, margin_pct, min_price, max_price_delta_pct, demand_signal |
listing_id |
InventoryAlerts |
listing_id, title, units, days_of_cover, kind (low_stock / slow_mover) |
kind |
PendingChanges |
change_id, kind, summary, status, before, after, margin_impact |
status |
Actions (run_action, both confirm-gated):
stage_price_update { listing_id, new_price, note }→ your endpoint writes a STAGED row, runs your guardrails (a move past yourmax_price_delta_pct, a protected field, an item cap) and returns{ change_id, before, after, margin_before, margin_after, guardrail_notes }. The confirmation card the operator sees IS the preview.apply_change { change_id }→ your endpoint re-runs the guardrails against the current configuration and refuses abeforethat no longer matches, then applies. Keep this one confirm-gated; never put it inautoRun.
Two properties you get from the platform rather than from your code: an
apply_change can only execute from a frozen, hashed action plan on a confirm
row the session's end user approved — text typed into the chat ("ok, apply
it") creates nothing; and every run is idempotent by a runtime-minted
actionId, so a retried approval cannot apply twice.
The operator IS the session's end user: run the agent in the dashboard debug session, or on a Telegram / WeCom channel where the confirm relay gives the requesting member the approve keyword. A separate approver — someone other than the person chatting — is not supported yet.
For the morning briefing, add a schedule (intervalMinutes: 1440) with the
prompt "Produce the morning briefing: what needs attention today and why";
the persona's briefing scene shapes the answer (3–6 items ranked by money at
stake, each with a figure and a next action).