$npx -y skills add AlpacaLabsLLC/skills-for-architects --skill product-spec-bulk-fetchFetch structured FF&E product specs from a list of URLs — extracts name, brand, dimensions, materials, price, and images into a standardized schedule. Use when the user provides product URLs and asks to "pull specs", scrape product pages, or bulk-import items by link.
| 1 | # /product-spec-bulk-fetch — Bulk Product Spec Fetcher |
| 2 | |
| 3 | Extract structured FF&E data from a list of product page URLs. Outputs a standardized schedule ready for design specs, procurement, or import into [Norma](https://norma.llc). |
| 4 | |
| 5 | ## Input |
| 6 | |
| 7 | The user provides product URLs in one of these ways: |
| 8 | |
| 9 | 1. **Inline list** — URLs pasted directly in the message (one per line, or comma-separated) |
| 10 | 2. **File path** — A `.txt`, `.csv`, or `.md` file containing URLs (one per line) |
| 11 | 3. **Google Sheet column** — A spreadsheet ID + column containing URLs to re-fetch |
| 12 | |
| 13 | If the input format is unclear, ask. |
| 14 | |
| 15 | ## Output Schema |
| 16 | |
| 17 | Products are written to the **master Google Sheet** — the same 33-column schema used by all product skills. When writing to CSV, use the same column order. |
| 18 | |
| 19 | Read `../../schema/product-schema.md` (relative to this SKILL.md) for the full column reference, field formats, and category vocabulary. Read `../../schema/sheet-conventions.md` for CRUD patterns with MCP tools. |
| 20 | |
| 21 | Skill-specific column values: |
| 22 | - **AF (Status):** `saved` |
| 23 | - **AG (Source):** `bulk-fetch` |
| 24 | - **AD (Tags):** Blank (set by user later) |
| 25 | - **AE (Notes):** Blank |
| 26 | - **T (Selected Color/Finish):** Blank (unknown from URL) |
| 27 | |
| 28 | ## Extraction Process |
| 29 | |
| 30 | For each URL: |
| 31 | |
| 32 | 1. **Fetch the page** using WebFetch with the prompt below |
| 33 | 2. **Parse the response** into the schema fields |
| 34 | 3. **Flag issues** — missing price, missing dimensions, non-product page |
| 35 | 4. **Continue to next URL** — never stop the batch on a single failure |
| 36 | |
| 37 | ### WebFetch Extraction Prompt |
| 38 | |
| 39 | Use this prompt (or close variant) for each URL: |
| 40 | |
| 41 | ``` |
| 42 | Extract structured product/furniture specification data from this page. Return a JSON object with these exact fields: |
| 43 | |
| 44 | - product_name: Full product name (Title Case) |
| 45 | - description: Short description or tagline (1-2 sentences), or null |
| 46 | - sku: Product ID, SKU, model number, or catalog number, or null |
| 47 | - brand: Manufacturer name (Title Case) |
| 48 | - designer: Designer or design studio name if attributed, or null |
| 49 | - vendor: The retailer/website selling the product (may differ from brand), or null |
| 50 | - collection: Product line or collection name, or null |
| 51 | - category: One of: Chair, Table, Sofa, Bed, Light, Storage, Desk, Shelving, Rug, Mirror, Accessory, Tabletop, Kitchen, Bath, Window, Door, Outdoor Furniture, Textile, Acoustic, Planter, Partition, Other |
| 52 | - width: Numeric width value only (no units), or null |
| 53 | - depth: Numeric depth value only (no units), or null |
| 54 | - height: Numeric height value only (no units), or null |
| 55 | - seat_height: Numeric seat height for seating products, or null |
| 56 | - unit: "in", "cm", or "mm" — whichever the page uses |
| 57 | - weight: Weight as stated with unit (e.g. "45 lbs"), or null |
| 58 | - materials: Comma-separated list of primary materials |
| 59 | - colors_finishes: Comma-separated list of ALL available colors or finish options |
| 60 | - list_price: Numeric price (no currency symbol, no commas), or null |
| 61 | - sale_price: Discounted/sale price if shown, or null |
| 62 | - currency: "USD", "EUR", "GBP", etc. |
| 63 | - lead_time: Delivery estimate as stated, or null |
| 64 | - warranty: Warranty info as stated, or null |
| 65 | - certifications: Comma-separated certifications (GREENGUARD, FSC, BIFMA, etc.), or null |
| 66 | - com_col: "COM", "COL", "COM/COL" if mentioned, or null |
| 67 | - indoor_outdoor: "Indoor", "Outdoor", or "Indoor/Outdoor" if specified, or null |
| 68 | - image_url: URL of the primary product image (largest/hero image) |
| 69 | |
| 70 | If this is NOT a product page, return: {"error": "not_a_product_page"} |
| 71 | If dimensions use a combined format like "32 x 24 x 30 in", split them into W x D x H. |
| 72 | If price says "Contact for pricing" or similar, set price to null. |
| 73 | Return ONLY the JSON object, no other text. |
| 74 | ``` |
| 75 | |
| 76 | ## Workflow |
| 77 | |
| 78 | ### Step 1: Parse input |
| 79 | Extract all URLs from the user's input. Report count: "Found N product URLs." |
| 80 | |
| 81 | ### Step 2: Fetch in parallel |
| 82 | Process URLs using WebFetch. Use parallel tool calls — fetch up to 5 URLs simultaneously to maximize speed. Report progress after each batch. |
| 83 | |
| 84 | ### Step 3: Compile results |
| 85 | Build a results table. Group into: |
| 86 | - **Successful** — all key fields extracted |
| 87 | - **Partial** — some fields missing (still include in output) |
| 88 | - **Failed** — non-product page or fetch error |
| 89 | |
| 90 | ### Step 4: Present results |
| 91 | Show a summary table in markdown with all successful + partial results. Flag any issues: |
| 92 | - "Price not found" for trade/dealer sites |
| 93 | - "Dimensions not found" if missing |
| 94 | - "Failed to fetch" for errors |
| 95 | |
| 96 | ### Step 5: Ask about output format |
| 97 | Ask the user: **"Where should I save this?"** |
| 98 | Options: |
| 99 | - **Master |