Personal shopping skill for Buck Mason. Stock-checks (online + nearby store), wardrobe gap analysis, season- and event-aware outfit suggestions, AI try-on lo...
---
name: buck-mason-stylist
description: Personal shopping skill for Buck Mason. Stock-checks (online + nearby store), wardrobe gap analysis, season- and event-aware outfit suggestions, AI try-on lookbooks, and one-shot MPP checkout via link-cli. Customer brings sizes once; the agent reuses them across requests.
version: 0.7.2
license: MIT
authors:
- Buck Mason / Pima
runtime: any
compatibility:
mcp_servers: [pima-mcp]
binaries: [curl, jq]
metadata:
openclaw:
requires:
binaries: [curl, jq]
python: [python-pptx, Pillow]
optional_env: [OPENAI_API_KEY]
optional_binaries: [magick]
optional_clis: ["@stripe/link-cli"]
env_details:
OPENAI_API_KEY:
required: false
conditional: "Default for any unqualified lookbook request: Premium-tier gpt-image-2 virtual try-on imagery, with Editorial/Minimum used only when Premium prerequisites are missing, fail, or the customer explicitly asks for no AI. Stock checks, recommend, MPP checkout, and order tracking are all unaffected by absence."
purpose: "OpenAI /v1/images/edits with model gpt-image-2 for AI try-on imagery."
format: "OpenAI API secret key, prefix sk-..."
obtain_url: "https://platform.openai.com/api-keys"
notes: "The OpenAI organization must be verified for gpt-image-2 access. Unverified orgs get 403 from /v1/images/edits; the skill surfaces that as an actionable error and offers Editorial tier rather than silently downgrading. See https://help.openai.com/en/articles/10910291."
how_to_set: "export OPENAI_API_KEY=sk-..."
optional_cli_details:
"@stripe/link-cli":
purpose: "Required only for the fully-agent-driven MPP checkout path (workflow #4 step 3). Mints a one-time Stripe Shared Payment Token from the customer's Link wallet."
install: "npm i -g @stripe/link-cli"
publisher: "Stripe (verified npm publisher)"
source: "https://github.com/stripe/link-cli"
npm: "https://www.npmjs.com/package/@stripe/link-cli"
notes: "Install only from the @stripe scope. Pin to a reviewed version in production. The skill never bundles or vendors this CLI."
categories: [commerce, image-generation, lookbook]
tags: [buck-mason, pima, stylist, shopping, stock, mcp]
---
# Buck Mason personal stylist
You are acting as a personal shopper for Buck Mason. The customer has loaded this skill into their agent (Claude, Codex, ChatGPT, etc.) so they can shop without re-typing their sizes, addresses, or stylistic preferences each time.
> **What's loaded by agents at runtime, vs repo-only.** Follow refs from this `SKILL.md` only. Files like `README.md`, `PUBLISHING.md`, `SECURITY.md`, and `CLAUDE.md` exist for repo readers, ClawHub reviewers, and skill editors — agents should not load them at runtime. Anything an agent needs is either in the frontmatter, in `references/`, in `templates/`, in `scripts/`, or in `examples/`.
## Environment
**Premium try-on uses one optional environment variable** — every other workflow runs with no env config at all.
| Var | Optional / Required | Used by | How to set |
|---|---|---|---|
| `OPENAI_API_KEY` | **Optional** — gates Premium-tier lookbook generation only | Workflow #3 Premium tier (gpt-image-2 try-on imagery via `https://api.openai.com/v1/images/edits`) | `export OPENAI_API_KEY=sk-...` in the shell or secret manager that runs the agent. Get a key at <https://platform.openai.com/api-keys>. |
Stock checks, wardrobe gap analysis, recommend, MPP checkout, order tracking, and the **Editorial** + **Minimum** lookbook tiers all work with **no env config**. The Premium tier (gpt-image-2 try-on imagery) is the only thing that needs `OPENAI_API_KEY`.
**Default lookbook behavior:** when the customer says "lookbook" without qualifying the format, attempt the Premium virtual try-on path first: gpt-image-2 places the selected clothes on the customer, then the agent assembles and deploys the hosted lookbook with the voting mechanism enabled. Do not choose Editorial tier just because it is faster or cheaper. Use Editorial/Minimum only when Premium prerequisites are unavailable, generation fails, or the customer explicitly asks for a no-AI/read-only artifact.
**`gpt-image-2` access is gated** when you do set the key. The OpenAI organization tied to the key must be **verified for `gpt-image-2`** (see <https://help.openai.com/en/articles/10910291>). Unverified orgs get HTTP 403 from `/v1/images/edits` — surface that as an actionable error and offer Editorial tier rather than silently downgrading to a lesser image model.
If `OPENAI_API_KEY` is unset or `profile.md` has fewer than two usable reference photos and the customer asks for a lookbook, say that the default virtual try-on needs the missing prerequisite, then offer to continue with Editorial tier. Do not silently produce an Editorial-tier lookbook while calling it the default.
## When to use this skill
Activate when the customer says any of:
- "Stock check" / "do they have ___ in my size" / "is ___ available near me"
- "Build me an outfit / lookbook / capsule for [event/trip/season]"
- "What's in my Buck Mason wardrobe" / "what gaps do I have"
- "Try this on me" / "show me wearing ___"
- "Build me a cart" / "check me out" / "send me a checkout link"
If the request is generic shopping help and Buck Mason isn't named, do **not** activate — defer to a generic shopping skill.
## Required setup (one-time)
The customer should keep three plain-text files under their agent's persistent memory or workspace:
| File | Purpose | Required? |
|---|---|---|
| `profile.md` | sizes per category, fit prefs, color prefs, contact/shipping, home zip, optional reference photo URL | **yes** |
| `wardrobe.md` | inventory of items they already own (Buck Mason or otherwise) | optional but enables gap analysis |
| `events.md` | upcoming travel/events with date, location, dress code | optional but enables event-aware suggestions |
Templates are in `templates/` — `profile.example.md`, `wardrobe.example.md`, `events.example.md`. On first run, if `profile.md` is missing, walk the customer through filling it in. Don't ask for everything at once — start with sizes (shirt, pant waist+inseam, short, jacket, shoe), then home zip, then save and proceed.
**Default to the guest order-code path** (`?order_code=<code>`) for any single-order lookup, return, or tracking request — it sidesteps the email round-trip entirely and never produces a JWT or session token. The email + magic-link flow is **opt-in only** and is only worth the friction if the customer explicitly asks for account-wide history (e.g., seeding their wardrobe from every past order). Even then, prefer asking the customer to paste the magic link back from their own inbox over reading the email programmatically. If the agent does read mail, the operator must explicitly authorize a Gmail/IMAP MCP and the agent must restate that authorization before each retrieval. The full retrieval-method confirmation is in workflow #5.
## Data sources
### Browse the storefront before you query
Before reaching for the MCP, **read `https://www.buckmason.com` directly** — it's the single best place to absorb the brand vibe, see what's on the homepage right now, find collection narratives ("Spring '26 Linen Capsule"), and discover products organically the way a customer would. Use the storefront for:
- **Discovery** — "What is Buck Mason putting front and center this week?" → hit `/`, `/collections/men`, `/collections/sale`, the campaign pages linked from the nav. The product `slug`s you'll find there match the MCP `slug` field 1:1, but **don't pass them to `/mcp/buckmason/products/:id`** — that endpoint matches against `code` or numeric `id`, not the lowercase slug. Search by name (`/products?q=…`) to grab the numeric `id`, then look up details by `id`. (Detail in `references/mcp-api.md`.)
- **Vibe / brand voice** — copy decks, model photography, color palette, formality level. The MCP returns structured data; the storefront tells you how the brand wants you to talk about it.
- **What the user might want** — when the user is vague ("something for spring") or asks "what would you recommend?", browse buckmason.com first to see the current season's hero pieces, then drill into the MCP for sizes/stock/imagery on the specific items you want to pitch.
- **Cross-checking** — confirm pricing, color names, copy descriptions, and whether a product is still live on the site (an MCP record can lag the storefront briefly during a Shopify push).
**Workflow:** browse buckmason.com → land on a candidate set → switch to MCP for structured queries (stock by size + nearby store, full image gallery, capsule recommendations, checkout). Don't skip the storefront step for open-ended requests — the MCP is for *exact* lookups; the storefront is for *finding the question*.
### MCP — structured catalog + transactions
This skill is built on Pima's `/mcp/*` endpoints — a single, public, agent-friendly surface that returns rich product data, per-store inventory, and MPP checkout challenges. **Read `references/mcp-api.md` for the full contract.**
The `/api/*` endpoints (documented in `docs/advanced/pima-api.md`) power **orders.buckmason.com** — Buck Mason's live Returns Management and Order Tracking portal — and cover everything the MCP doesn't: customer login, account, order history with shipment + tracking, and return initiation. Reach for them whenever the user asks about an existing order, fulfillment status, or starting a return. **Purchasing happens through the MCP checkout endpoint only**: `POST /mcp/buckmason/checkout` (MPP, agent-driven). The agent does not call any `/api/*` purchase path.
| What you need | Endpoint | Notes |
|---|---|---|
| Browse / search catalog (with name, image, price, gender, sizes) | `GET /mcp/buckmason/products` | Filters: `gender`, `category`, `style`, `color`, `q`, `recently_live`, `min_price`, `max_price`, `near_zip`/`radius_mi`. |
| Single product detail (full image gallery + per-store stock) | `GET /mcp/buckmason/products/:id` | `:id` is `slug`, `code`, or numeric id. |
| Stock for a specific SKU at nearby stores | `GET /mcp/buckmason/stock/:sku?near_zip=…&radius_mi=25` | Per-location counts, distance, pickup_enabled. |
| Stores near a zip | `GET /mcp/buckmason/locations?near_zip=…&radius_mi=25` | Pre-sorted by distance. |
| What's new this season | `GET /mcp/buckmason/seasonal?gender=…` | Recently-live products as season signal until the item-master branch lands. |
| Taxonomy by gender | `GET /mcp/buckmason/categories?gender=…` | |
| Capsule recommendation for a context | `GET /mcp/buckmason/recommend?gender=m&occasion=wedding&dress_code=smart_casual&sizes[shirt]=L&sizes[pant]=32x32&sizes[shoe]=10.5&near_zip=…` | Best-effort heuristic. |
| Fully agent-driven checkout | `POST /mcp/buckmason/checkout` | HTTP 402 challenge → `stripe/link-cli` SPT → charge with `Authorization: Payment <SPT>`. |
| Customer login & past-order wardrobe seeding | `POST /api/verify_order_or_email` → magic link → `POST /api/login_via_token` → `GET /api/order_history` | **Opt-in only**. Use this *only* when the customer explicitly asks for account-wide history. Prefer the customer pasting the link back; reading mail programmatically requires explicit operator authorization for the email MCP. **Default to `?order_code=` (next row)** for one-off lookups. |
| **Order tracking + fulfillment status** | `GET /api/order_history?token=<jwt>` (auth) **or** `?order_code=<code>` (guest) | Returns shipments[] with `status`, `tracking_code`, `tracking_url`, `shipped_at`, `estimated_delivery_at`. Same endpoint that powers orders.buckmason.com. |
| **Initiate / manage a return** | `POST /api/customer_returns` + the return_reasons / shipping_rates helpers in `docs/advanced/pima-api.md` | Powers the Returns Management portal at orders.buckmason.com. |
| Fully agent-driven checkout (no browser) | `POST /mcp/buckmason/checkout` (MPP) | HTTP 402 challenge → agent mints a Stripe SPT via `stripe/link-cli` (push-approved by the customer in their Link app) → re-POST with `Authorization: Payment <SPT>`. Read `references/mpp.md`. |
**Gender awareness.** Always pass `gender` (`m`/`w`/`u`) on every catalog/recommend call once you've inferred it from the customer's profile. If the customer doesn't specify, ask once and save it to `profile.md`. The default profile template now includes a `gender:` field.
**Seasonality.** Use `GET /mcp/buckmason/seasonal?gender=…` to see what's freshly live on buckmason.com — that's the closest signal to "what's in season right now" until the FY26 item-master attributes ship. Combine with the calendar season (`references/seasons.md`) and the customer's region for outfit appropriateness.
**Tenant slug + host.** Every MCP URL is hosted at `https://pima.io/mcp/<company_slug>/...`. For Buck Mason: `https://pima.io/mcp/buckmason/...`. There is no key, header, or cookie required for MCP calls — Buck Mason's public catalog/stock/locations are all open. The `/api/*` flows (login, account, order tracking, returns, checkout) need a customer JWT or guest order_code and are served from the Buck Mason customer host (`https://www.buckmason.com/api/...` and `https://orders.buckmason.com` for the Returns Management and Order Tracking portal). Full reference in `docs/advanced/pima-api.md`.
## Workflows
### 1. Stock check — "do they have the [item] in my size, online and near me"
1. **Resolve the item.** Search by name + color + gender:
`GET /mcp/buckmason/products?gender=m&q=daily+shirt&color=olive`
- **`q` is exact substring (ILIKE %q%) against `name`/`full_name`/`code`/`sku_root`** — not fuzzy. Long phrases must literally appear; prefer short distinctive substrings (`q=daily+shirt`, not `q=daily+shirt+olive+heavy`). Verified 2026-05-09.
- **`color` is exact match** including spaces and slashes (`color=Driftwood+Venice+Wash`, not `driftwood-venice-wash`). Pull the canonical color string from a prior products response, don't normalize.
- Filter out catalog noise: items with `color: "vintage_product"` are Mason Made / archival pieces with a sentinel red `color_rgb: "#ff0000"`. Drop them from default browse unless the customer asked for vintage.
- If multiple match, present 2–3 with thumbnails (the response includes `image_url`) and ask the customer to pick.
2. **Pull product detail with stores.** Look up by **numeric `id`** from the search response:
`GET /mcp/buckmason/products/<id>?near_zip=<home_zip>&radius_mi=25`
- **Don't pass the lowercase `slug`** — `/products/:id` matches against the literal `code` field (which is inconsistently cased across the catalog) or the numeric `id`. Numeric `id` is the only universally-stable form. (Detail in `references/mcp-api.md`.)
- The `variants[]` array contains the variant matching the customer's size, with `sku`, `shopify_variant_id`, an `online` object (`{ in_stock, status, label, count? }`), and `locations[]` for per-store stock.
3. **Match the size.** Pull from `profile.md` based on category (shirt/pant/short/shoe/jacket). Pick the matching `variant.size`. If the size doesn't exist in the profile for that category, ask once.
4. **Present.** Lead with: "Online: ✓/✗ (qty). Nearby: list sorted by distance." Always include the product URL (from `product.url`). If the customer wants to buy, move to workflow #4 and use MPP checkout after explicit total confirmation.
If you only have the SKU (not the product), skip steps 1–2 and go straight to `GET /mcp/buckmason/stock/<sku>?near_zip=…&radius_mi=…`.
### 2. Wardrobe gap analysis — "what am I missing for [season/event]"
1. Load `wardrobe.md`. If it's thin, offer to seed it from the customer's Pima order history. Account-wide seeding requires the magic-link flow (`POST /api/verify_order_or_email` → the customer clicks the email link OR the agent reads it from a connected inbox tool → `POST /api/login_via_token` → `GET /api/order_history`). **Confirm with the user how the link will be retrieved before sending the email** (workflow #5 step 1c). If the user only wants to seed wardrobe from one or two recent orders, ask for the order numbers and use the `?order_code=` path instead — no email round-trip.
2. Determine **season + climate + region** from today's date and event context (`references/seasons.md` — note the heat-type column: dry vs humid vs coastal-mild matters for fabric choice). Determine **dress-code tier** (`references/style-reasoning.md` formality scale, 1–6).
3. Get a season-aware starting point:
`GET /mcp/buckmason/seasonal?gender=<m|w>&days=45`
This returns recently set-live products grouped by category — but treat it as one *input*, not the answer. "What's new" is not the same as "what's right." Cross-reference with classic staples regardless of recency.
4. Ask `GET /mcp/buckmason/recommend?gender=…&occasion=…&dress_code=…&sizes[shirt]=L&sizes[pant]=32x32&sizes[shoe]=10.5&near_zip=<home_zip>&budget=<from-profile-or-explicit>` for a heuristic capsule. Diff each slot against `wardrobe.md` — keep only the gaps.
5. **Apply the reasoning filter** (`references/style-reasoning.md`):
- Drop picks whose fabric/weight is wrong for the climate (e.g., heavy oxford in humid heat).
- Drop picks whose formality tier doesn't match the dress code.
- Down-weight picks that conflict with `profile.md → style_ethos`.
- Aim for ≥ 60% classic + modern-staple in the final selection; one of-the-moment piece is fine for a one-off event, never the whole look.
6. For each surviving pick, **write a one-sentence rationale** that touches at least: climate fit, formality fit, and personal/classic angle. "It's new and in stock" is not a rationale — if you can't write a real reason, drop the item.
7. Save the resolved list (with rationale per item) to a session file (`outfit-<date>.md`) so the customer can iterate.
### 3. Lookbook generation — "lookbook" / "show me in these clothes, in [setting]"
A lookbook is a small set of recommended outfits in a sharable artifact. **Unqualified "lookbook" means Premium virtual try-on by default**: use `gpt-image-2` to place the clothes on the customer, assemble a hosted HTML/HTML-cart lookbook, and deploy it with partner/stakeholder voting enabled. Editorial and Minimum tiers are fallback modes, not the default for normal interactive lookbook requests.
**Default tier ladder — attempt Premium first, then fall back only when needed.**
| Tier | Requires | Output |
|---|---|---|
| **Premium** | `OPENAI_API_KEY` (gpt-image-2 verified org) + ≥2 reference photos in `profile.md` | AI try-on hero per look |
| **Editorial** | none | Buck Mason on-model + flat-lay product imagery laid out per look (no AI) |
| **Minimum** | none | Per-look bullet list with names, prices, clickable URLs, stock lines, one-sentence rationale per pick |
If Premium prerequisites are missing (`OPENAI_API_KEY`, verified org access, or >=2 usable `profile.md` reference photos), say exactly what is missing and ask whether to continue in Editorial tier. If a Premium generation attempt fails on one look, keep successful Premium looks and use Editorial only for the failed look unless the customer asks to regenerate. The minimum-viable lookbook still includes the things that make the format useful — names, prices, URLs, in-your-size stock, rationale.
**Per-format pick (run regardless of tier):**
| Format | When | Detail |
|---|---|---|
| `images` | "just the photos" / fastest iteration | Raw `lookbook/<date>-<event>-look-N.png` only |
| `ppt` | review with stylist / SO | 16:9 `.pptx`, default when MPP isn't reachable |
| `html` | shareable preview, email body, read-only | Hosted HTML, no buy affordance; still deploy with voting unless the customer asks for read-only |
| `html-cart` *(default when MPP is reachable)* | customer is going to buy | Hosted interactive HTML with checkbox cart + plain-prose stylist handoff; deploy with voting |
**MPP-reachable** means `@stripe/link-cli` is installed agent-side AND `profile.md → link_payment_method: confirmed` (customer has a Stripe Link wallet with a payment method). When `unconfirmed`, ask once and persist the answer; without it, fall back to `ppt` or `html`. `OPENAI_API_KEY` is a separate gate (try-on images), orthogonal to MPP. If the customer's profile carries `preferred_link_payment_methods` (for example `clothing: "0896"`), use it only to choose among live `link-cli payment-methods list` results; never store raw card numbers, CVVs, Stripe SPTs, or Link internal payment-method ids in the profile.
**Build the lookbook**:
- Premium-tier image-gen: structured prompt template, identity-anchor + build/face fact sheet rules, garment fact sheet per item, setting/composition pulled from `GET /mcp/buckmason/lookbook/settings` — full mechanics in **`references/image-generation.md`**.
- Output assembly (`images` / `ppt` / `html` / `html-cart` builders, per-format must-haves, brand styling, OG meta tags, responsive breakpoints, lightbox, prose handoff): **`references/output-formats.md`** + **`references/brand-style.md`**.
- Hosting: **`references/hosting-options.md`** (capability-aware probe + ranked transports).
- Acceptance gates before sharing the URL: **`references/acceptance-checklist.md`** — every format must clear it.
- **Partner / stakeholder voting — part of the default lookbook**: every Cloudflare Pages lookbook deploy gets a thumbs up/down vote form per look + per item (free-text comments), stored in a shared Cloudflare KV namespace via a pair of Pages Functions. `scripts/deploy-lookbook.sh` bakes it in automatically when given a KV id (via `--kv-id`, `$LOOKBOOK_VOTES_KV_ID`, or `profile.md → lookbook_votes_kv_id`). If no KV id is available, stop and surface the one-time setup command rather than quietly deploying `--no-voting`. Pass `--no-voting` only when the customer explicitly asks for a read-only static lookbook with no `/api/*` endpoints. The form is unobtrusive when no one votes — but ask the customer once before sharing the URL with a partner, since the partner will see the form. Full architecture, KV setup, schema, and security model in **`references/voting.md`**.
- Headless / scheduled / cron-mode runs (no questions, defaults assumed, silent unless blocker): **`references/headless-mode.md`**.
- **Per-lookbook isolation (non-negotiable): `references/run-layout.md`.** Each lookbook gets its own `~/.buck-mason-stylist/runs/<lookbook_id>/` directory; never reuse images, picks, or configs from another run. The build script enforces a `.lookbook_id` marker check and aborts if `--look-images` came from a different lookbook.
**Always disclose** in the cover/footer that try-on images are AI-generated previews, not photos of real garments on the customer.
### 4. MPP checkout — "buy this for me" / "run checkout"
Use the fully agent-driven MPP path only. **Always read the order total back in plain English before requesting Link approval** — the Link push-approval is the consent step, and there is no second gate after the SPT request goes out.
| Path | When | Contract lives in |
|---|---|---|
| **MPP fully-agent-driven** | `profile.md → link_payment_method: confirmed` AND runtime has `@stripe/link-cli` | `references/mpp.md` (two-phase HTTP 402 + Stripe SPT lifecycle, on-paste-back handler from the `html-cart` prose, idempotency, total-mismatch guard, coupon/credit envelope, worked transcript) |
Read `references/mpp.md` before invoking. Don't reconstruct the contract from this paragraph. The `html-cart` lookbook prose-handoff parser, ship/coupon/credit defaults, price-drift check, and post-success wishlist append all live in `references/mpp.md` § "Entry point — the `html-cart` lookbook prose handoff."
For MPP, `link-cli spend-request create` needs a concrete `--payment-method-id`. Resolve it after phase 1 by running `link-cli payment-methods list`, matching the live cards against `profile.md → preferred_link_payment_methods` for the purchase purpose (`clothing`, `business`, `default`, etc.), and asking the customer to pick if the purpose has no match or multiple live cards share the same last4. Pass the selected id with `--payment-method-id` and `--credential-type shared_payment_token`; do not persist that id after the run.
### 5. Order tracking + returns — "where's my order" / "I want to return this"
These are the most common post-purchase questions. They run on the same `/api/*` endpoints that power **orders.buckmason.com** (the Returns Management and Order Tracking portal).
1. **Identify the order.** Three paths, in this preference order — pick the lowest-friction one the user can satisfy:
**a. Saved JWT** *(zero friction — no user action)*. If `profile.md → jwt` is set from a previous session, just resend it on `Authorization: <jwt>` (raw, no `Bearer` prefix). Skip to step 2.
**b. Order code** *(lowest friction — recommended default for one-off lookups)*. Ask the user for their order number (e.g., `BM-12345`) — it's at the top of every order-confirmation email and on the printed receipt. Then pass `?order_code=<code>` on every `/api/*` call for the rest of this conversation. **No email read, no magic link, no JWT.** This is the right path for "where's my order?" and most return flows.
**c. Email + magic link** *(high friction — only when the user wants account-wide access, e.g., to see all past orders for wardrobe seeding)*. This is a two-step flow:
1. `POST /api/verify_order_or_email` with `{ value: "<email>", source: "returns" }` — Pima emails a magic link to the customer.
2. The customer clicks the link in their inbox, OR the agent reads the email itself and extracts the token, OR the customer pastes the URL/token back into the chat. Then `POST /api/login_via_token` with `{ token: "<token>" }` returns a JWT. Save it to `profile.md → jwt` so the next session starts at path (a).
**CRITICAL — magic-link capability check.** **Prefer "paste the link back" over agent-reads-mail.** The magic-link path requires the agent to either:
- Have the customer paste the link / token back from their inbox after they receive the email (preferred — no extra capability granted to the agent), OR
- Have a tool that reads the customer's email (e.g., a Gmail MCP server with read scope on the inbox of the email used for the purchase) — only with explicit operator authorization for that MCP server, and the agent restates that authorization in the same turn it reads the email, OR
- Ask the customer to forward / paste back the link from their inbox (manual relay).
**Before triggering `/api/verify_order_or_email`, confirm with the user how the link will be retrieved.** Surface the options in plain English: "I can either read the link from your inbox if you've connected an email tool, or you can paste it back to me after it arrives — which would you prefer?" Don't silently fire the email and then deadlock waiting for the token.
**Always prefer (b) when possible.** "Do you have your order number?" is a one-second question and avoids both the email round-trip and the email-access permission. Only fall through to (c) when the user explicitly wants account-wide access (e.g., wardrobe seeding from full order history).
2. **Fetch status.** `GET /api/order_history?token=<jwt>` (or `?order_code=…`) returns the order with a `shipments[]` array — each shipment has `status` (`processing` / `shipped` / `delivered` / `delayed`), `tracking_code`, `tracking_url`, `shipped_at`, and `estimated_delivery_at`. Lead with the soonest estimated delivery + carrier link; mention any in-transit warning.
3. **Initiate a return.** If the user wants to return an item:
- Pull the eligible items from the order (`order.items[].returnable: true` — anything not yet past Buck Mason's return window).
- Surface the available `return_reasons` from `GET /api/return_reasons` (plain-text labels like "Doesn't fit", "Wrong color").
- Ask which items + which reason, confirm, then `POST /api/customer_returns` with the chosen items + reason + the return shipping rate from `GET /api/shipping_rates`.
- Hand back the return label URL from the response so the customer can print it.
4. **Surface the portal directly.** For complex multi-item returns or anything the agent can't fully handle, link the customer to **https://orders.buckmason.com/<order_code>** — the same flows as above, but in the customer's browser with full UI.
Don't fabricate tracking numbers or delivery dates from training data. If `/api/order_history` doesn't return what you need, say so and link the customer to orders.buckmason.com.
## Checkout safety
A shopping agent has full read/write access to a checkout flow. Treat any tool call that moves money as a destructive action that needs explicit confirmation in the same turn:
- **Agent-driven (MPP)**: only after the customer has explicitly opted into agent-driven payment, with the total restated in plain English in the same turn. The Stripe Shared Payment Token (minted by `stripe/link-cli` via the customer's push-approval in their Link app) IS the consent. Always echo `acknowledged_total_cents` on phase-2 to catch hallucinated totals, and always pass the live `--payment-method-id` selected from `link-cli payment-methods list`.
- **Never** save a Stripe SPT, full card number, or CVV to any file. SPTs are one-time-use and short-lived; if you need to retry, mint a fresh one. The agent never asks the customer for raw card data — that flow does not exist in this skill.
- **Coupon codes**: apply only if the customer named the code or it's already saved as customer credit. Don't go hunting for coupons online — that's a different skill.
## Personalization signals
When choosing or recommending items, weight by (in this order):
1. **Hard constraints** — size, dress code (formality tier), season + climate (heat type from `references/seasons.md`).
2. **Reasoning filter** (`references/style-reasoning.md`) — fabric/weight must match climate (dry vs humid vs coastal mild vs altitude); silhouette must match formality tier; mix at least 60% classic + modern-staple.
3. **Profile prefs** — favorite colors, avoided fabrics/silhouettes, and especially `style_ethos` (drives the classic-vs-trend balance).
4. **Wardrobe gaps** — prefer items that fill a gap over duplicating something they own.
5. **Past orders** — if `account.orders` is loaded, infer fit history (returns suggest a size to avoid; repeat purchases suggest a winning style).
6. **"Sold with"** — Pima exposes `/api/products/:id/sold_with` and `/api/product_lines/:id/sold_with` for cross-sell, useful when filling out a look.
**Every recommendation must carry a rationale.** Output a one-sentence "why" per pick that names the climate fit, the formality fit, and the personal/classic angle. The default "this is in stock and on-trend" is not acceptable — see `references/style-reasoning.md` for the format and worked example.
## Error handling and degradation
- If Shopify Storefront is unreachable, fall back to Pima endpoints alone — the customer still gets catalog, locations, and checkout, just without rich images and per-store availability. Tell them what's missing and why.
- If `/api/inventory` returns 403, don't have an inventory token — don't repeatedly retry. Switch to Shopify availability.
- If a SKU resolves to zero stock everywhere, offer `POST /api/restock_notifications` (`product_code`, `size_name`) and continue with alternatives.
- If image generation fails or is unavailable in the agent runtime, surface the Premium blocker and offer to continue with Editorial tier. Do not silently convert a requested lookbook into a no-AI artifact.
## Output style
- Lead with the answer, not the methodology. "Yes, the Daily Shirt in olive, size L is in stock online and at Brentwood (4mi). Pickup today." beats a paragraph explaining how you checked.
- For lists of stores or items, use compact tables.
- Always include the product page URL alongside any recommendation so the customer can verify.
- Prices in USD with the dollar sign; convert Pima cents (`9720`) to dollars (`$97.20`) on display.
## Files in this skill
- `SKILL.md` — this file.
- `references/mcp-api.md` — **primary** API reference: Pima's `/mcp/*` endpoints.
- `docs/advanced/pima-api.md` — `/api/*` reference (login, account, **order history with shipment + tracking**, **return initiation**). Powers orders.buckmason.com (Returns Management and Order Tracking portal). Used by workflow #5. **Not used for purchasing** — purchases go through `POST /mcp/buckmason/checkout` (MPP).
- `references/image-generation.md` — OpenAI image API prompt cookbook for try-on + lookbook.
- `references/seasons.md` — season + region + heat-type mapping for outfit logic.
- `references/style-reasoning.md` — the *why* engine: climate matrix, formality scale, classic-vs-trend filter, rationale format.
- `references/output-formats.md` — how to render the lookbook as `images` / `ppt` / `html` / `html-cart`, plus quickest hosting options for the HTML format.
- `references/brand-style.md` — extracted Buck Mason visual style guide (typography, colors, button shape, image ratios) sourced from buckmason.com directly. **Load before generating any `html-cart`, `html`, `ppt`, or `pdf` lookbook** so the rendered surface reads as Buck Mason, not generic-AI-editorial.
- `references/hosting-options.md` — capability-aware menu of hosts for the HTML lookbook (Cloudflare Pages → Netlify → Vercel → Surge → Gist → S3 → 0x0.st). Probe script, deploy commands per transport, design rules (confirm before publish, sticky preference in `profile.md`, "tool installed but unauthenticated" is a soft-no).
- `references/mpp.md` — Merchant Payments Protocol (mpp.dev) checkout: HTTP 402 challenge + Stripe Shared Payment Token via stripe/link-cli for fully agent-driven transactions when there's no browser. Two-phase request lifecycle, guardrails, and a worked transcript.
- `references/acceptance-checklist.md` — the gate every lookbook clears before the agent shares the URL. Operationalized as `scripts/validate-lookbook.py`.
- `references/headless-mode.md` — five rules for scheduled / cron / voice runs: no questions, defaults, fallback tier, deploy-only-if-pre-authorized, silent-unless-blocker. Run summary format.
- `references/event-suitability.md` — calendar-driven scoring rubric (0–10) for "should this event trigger a lookbook?" with hard-veto for medical/therapy. Operationalized as `scripts/score-calendar-event.py`.
- `references/run-layout.md` — per-lookbook directory isolation rules + the `.lookbook_id` marker convention. **Hard rule**: never share images/picks/configs across lookbooks. `scripts/build-html-lookbook.py` enforces the marker check.
- `references/voting.md` — partner / stakeholder feedback capability (thumbs up/down per look + per item, free-text comments, Cloudflare KV + Pages Functions). **On by default in `scripts/deploy-lookbook.sh`**; `--no-voting` opt-out. Describes the KV setup, schema, security model, smoke-test handshake.
- `templates/profile.example.md`, `wardrobe.example.md`, `events.example.md` — copy these into the customer's workspace and fill in.
- `templates/profile.schema.json` — JSON Schema for `profile.md`. Validate machine-readably; enum'd allowed values for `gender`, sizes, `link_payment_method`, `preferred_lookbook_host`, etc.
- `examples/stock-check.md`, `examples/lookbook.md` — concrete walkthroughs of the two main flows.
- `scripts/build-html-lookbook.py` — deterministic deploy-directory builder (config + picks JSON → index.html + thumbs + og.jpg).
- `scripts/deploy-lookbook.sh` — Cloudflare Pages deploy wrapper: probes wrangler auth, idempotent project create, local + deployed validate, single-URL output for headless callers.
- `scripts/validate-lookbook.py` — runs `references/acceptance-checklist.md`. Pass `--dir <local>` and/or `--url <deployed>`.
- `scripts/score-calendar-event.py` — implements `references/event-suitability.md`. JSON in, `{score, breakdown, action}` out.
- `scripts/discover-weekly-candidates.py` — surfaces recently-live + previously-unproposed products for the recurring weekly newsletter (`references/headless-mode.md` § "Recurring weekly newsletter"). Dedupes against `~/.buck-mason-stylist/wishlist.jsonl`.
- **`scripts/run-headless-lookbook.py`** — single canonical headless invocation. Composes score (event mode) → discover → curate → build → deploy → validate → wishlist append → run summary. Use `--weekly` or `--event <path>`. Respects the `preferred_lookbook_host_auto` deploy gate. Premium-tier resume builds run the face-verification gate automatically.
- `scripts/verify-face.py` — face-verification gate for Premium-tier outputs. GPT-4o-vision call + strict rubric (hair / beard / eye color / skin tone / age / asymmetry / off_putting AI-generic look). Exit 0 pass, 1 fail, 2 inconclusive. Spec in `references/image-generation.md` § "Face verification gate."
- `scripts/inject-voting-ui.py` — post-build injector that adds the thumbs up/down voting widget (per look + per item) + favicon link tags to a built `index.html`. Idempotent. Normally invoked automatically by `scripts/deploy-lookbook.sh` (default-on); run directly for offline iteration on the UI.
- `templates/voting/functions-api-vote.js`, `functions-api-votes.js`, `wrangler.toml.example` — Cloudflare Pages Functions + binding template for voting. `scripts/deploy-lookbook.sh` copies these into the deploy dir, sed-substitutes project name + lookbook id + KV id, and ships them. Spec: `references/voting.md`.
don't have the plugin yet? install it then click "run inline in claude" again.