One .zip per skill. Inside: SKILL.md with the intent and the frontmatter, and the code that runs in the page.
Settings → Personalize → Skills. This is Cowork's own skill library, shared across every chat.
Click Add and choose the file you just downloaded. Cowork installs it once; no CLAUDE.md, no per-project setup.
The skill stays available in every session. Cowork runs it in your own Chrome, riding the session you are already signed into.
Search Yelp for local businesses by term and location, with rating and price.
{"query":"string (what to search, e.g. 'coffee' or 'plumber')","location":"string (city or address, e.g. 'San Francisco, CA')"}{"count":"int","results":"array of { name, slug, url, rating, reviews, price }"}Search Yelp for local businesses by term and location. Navigates the search results page and reads the rendered business cards in the browser (Yelp's DOM is obfuscated, so this keys off the stable /biz/ heading links and the star-rating aria-labels). Params: query (e.g. 'coffee' or 'plumber'), location (city or address, e.g. 'San Francisco, CA'). Returns {count, results:[{name, slug, url, rating, reviews, price}]}. Read-only.
params. It does the in-page work and returns the JSON in returns.( async (root, params) => { const doc = root && root.querySelectorAll ? root : document; const txt = (el) => el ? (el.innerText || el.textContent || '').trim() : null; const heads = Array.from(doc.querySelectorAll('h3 a[href*="/biz/"], h4 a[href*="/biz/"]')); const seen = new Set(); const results = []; for (const a of heads) { const slug = ((a.getAttribute('href') || '').split('/biz/')[1] || '').split('?')[0].split('/')[0]; if (!slug || seen.has(slug)) continue; seen.add(slug); let card = a; for (let i = 0; i < 10 && card.parentElement; i++) { card = card.parentElement; if (card.querySelector('[aria-label*="star rating"]')) break; } const ratingEl = card.querySelector('[aria-label*="star rating"]'); const rm = ratingEl ? (ratingEl.getAttribute('aria-label') || '').match(/([\d.]+)/) : null; let reviews = null; const revEl = card.querySelector('[aria-label$="reviews"], [aria-label$="review"]'); if (revEl) { const n = (revEl.getAttribute('aria-label') || '').replace(/[^\d]/g, ''); if (n) reviews = parseInt(n, 10); } if (reviews == null) { const mm = (txt(card) || '').match(/(?([\d,]{1,7}))?\s*(?:reviews?|reseñas?)/i); if (mm) reviews = parseInt(mm[1].replace(/[^\d]/g, ''), 10); } const priceEl = Array.from(card.querySelectorAll('span')).find((s) => /^$+$/.test(txt(s) || '')); results.push({ name: txt(a), slug, url: 'https://www.yelp.com/biz/' + slug, rating: rm ? parseFloat(rm[1]) : null, reviews, price: priceEl ? txt(priceEl) : null }); } return { count: results.length, results }; } )
{
"expr": "typeof result === 'object' && Array.isArray(result.results)",
"type": "value"
}