Files
unique/.claude/skills/daily-finds/SKILL.md
T
rzen f9bc8f93eb pipeline: relax hero floor to 2, keep ~4 as the soft aim
The real failure mode is 0-1 images (wall of text); two heroes read
fine on the 1-2 column layouts. Keep ~4 as the aim — prefer
hero-bearing candidates among equal fits, more images for bigger
bundles — since 2 among 8 items still looks thin on the wide
4-column grid. Restores the 3-item minimum bundle size.

Claude-Session: https://claude.ai/code/session_01WZaczDJjL3xZ3u5spsN5AL
2026-07-14 08:35:00 -04:00

14 KiB
Raw Blame History

name, description, disable-model-invocation
name description disable-model-invocation
daily-finds Capture-only daily sweep for unique.rzen.dev. Scans every source in sources.json, writes one find file per qualifying item to src/content/find/, marks the day's shortlist, adds Amazon affiliate links where the product is confidently matched, performs mechanical source maintenance, and nominates new sources. Does NOT write bundles or reviews — that's /build-bundle and /build-review (or /daily-pipeline for the whole chain). Use when the user asks for "today's finds", "morning sweep", "capture", or runs /daily-finds. true

daily-finds

Pure capture plus triage: every item that passes the bar becomes a find file, and the run ends by ranking the day's captures into a shortlist (up to 12) that drives downstream automation. Whether a find appears in a bundle or graduates to a review is still a separate step — but the shortlist is the pipeline's selection signal.

This skill is designed to run unattended. Never pause for confirmation mid-run; make the calls, log them, and surface anything odd in the end-of-run digest.

Invoke from inside the unique.rzen.dev repo.

Inputs

  • sources.json at the project root — curated source list with per-source fetch strategy (feed / webfetch / curl / skip), optional feedUrl (RSS/Atom) and fetchUrl.
  • daily-finds.log.md — running log of every find slug ever written (used to skip duplicates).
  • src/content/find/<year>/<month>/<slug>/index.mdx — already-captured finds (every existing slug is a "do not re-suggest" item; slugs are globally unique across years/months even though folders are nested by date).
  • src/content/reviews/<slug>/index.mdx — already-reviewed items (do not re-suggest).
  • candidate-sources.md — newly nominated sources awaiting user vetting.

The bar

A find qualifies if and only if it is (a) delightful, unusual, or distinctive in a way the audience would care about and (b) usable daily (relax to "memorable for a visitor" for travel). Drop generic mass-market items, ad-copy listicles, speculative / not-yet-shipping products, self-promo, and anything not traceable to a real currently-buyable / currently-visitable thing.

Crucially: do not filter by "is it the best of the day." Capture broadly. Selection happens in the shortlist step, and editorial treatment later.

Procedure

1. Scan every source

For each source in sources.json:

  • fetch: "feed" (preferred): curl -sL --max-time 25 -A "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.0 Safari/605.1.15" "<feedUrl>" and parse the RSS/Atom entries (title, link, summary, date). Consider only entries newer than the source's last productive run (when in doubt, the last ~30 days). Feeds bypass Cloudflare/HTML breakage — when a webfetch/curl source keeps failing, look for a feed and switch it over (see step 6).
  • fetch: "webfetch" or no field: WebFetch against fetchUrl if present, else url. Extract recently-featured items (name, link, one-line description).
  • fetch: "curl": shell out to curl with the Safari UA above against fetchUrl|url and parse the HTML (or JSON — e.g. Shopify products.json endpoints). Treat HTTP 403 with a non-empty HTML body as a content response — only treat empty bodies or Cloudflare challenge markers as blocked.
  • fetch: "skip": log the source as skipped (with skipReason) and move on. Do not retry (re-probing skipped sources is a step-6 quarterly job, not a per-run one).

Respect cadence: sources marked weekly / monthly / as-needed only need scanning when their cadence window has elapsed since the last productive scan — check the log; skip (and log as cadence-skipped) otherwise. This cuts run cost and rate-limit exposure.

Parallelize fetches in batches of ~8 concurrent requests; finish all sources before proceeding.

For each source record: items extracted, or empty / blocked / skipped / cadence-skipped.

2. Filter

For each extracted item, drop:

  • Anything whose slug already exists anywhere under src/content/find/ (find slugs are globally unique — check the leaf folder name across all <year>/<month>/ buckets).
  • Anything whose name appears anywhere in daily-finds.log.md.
  • Anything reviewed in src/content/reviews/ (compare by name field).
  • Items that fail the bar above.

3. Write find files

For every survivor, write one file at src/content/find/<year>/<month>/<slug>/index.mdx where <year> and <month> come from today's date. Hero image (when present) sits next to it as src/content/find/<year>/<month>/<slug>/hero.<ext>. The leaf folder name is the slug; URLs stay flat at /find/<slug>/ because the content-collection loader uses a leafSlug id derivation.

  • Slug: kebab-case form of the name (lowercase, ASCII, no leading numbers).
  • Frontmatter: name, subtitle (optional, one-liner), date (today), link (external URL — required), linkText (optional), source (the source name from sources.json — required, exact match), topics (1-3 values chosen from the controlled vocabulary in src/lib/topics.ts — the TOPIC_META keys; judge from the item itself, the source's topics in sources.json are hints only and may contain retired values; the build fails on anything outside the vocabulary; [] if nothing genuinely fits), tags (free editorial tags inferred from the item — keep to 2-4; add giftable when the item would make a genuinely good gift), description (optional meta override).
  • Body: 2-3 sentence note. Concrete, name a specific virtue. Bad: "great design". Good: "the silicone bumper means it survives drops onto concrete; the lanyard hole is positioned where your thumb naturally rests".
  • No daily cap — write every survivor.

If link for a Reddit-discovered item points at a v.redd.it / i.redd.it URL, fetch the post's selftext or comments to find the actual product URL before writing the file.

Supporting media

For every find, try to retrieve a single representative image from the linked page so the find has visual support if it later graduates to a review (or gets surfaced on a tile). Heroes also gate bundling — a bundle needs at least 2 hero-bearing items (aiming for ~4) before it can ship — so a find without a hero can hold a whole theme back: try a second source (developer site, App Store, Wikimedia) before giving up. The quality bar below still wins, though — a bad image is worse than none.

  • Where to look (in priority order): og:image meta tag → JSON-LD image field → main product photo / hero image markup → first article image.
  • Where to save: src/content/find/<year>/<month>/<slug>/hero.<ext> — colocated next to index.mdx. Preserve the original extension (.jpg, .png, .webp, .gif, .avif). One file per find — hero is the canonical name.
  • What to skip: images with marketing/sales overlay text (Amazon-style "BEST PRESS / NO GRIT" tags), tiny thumbnails (<400px on the long edge), generic site logos, paywalled CDN URLs that 403 to curl. If the only available shots are marketing collages, skip rather than save a noisy image — a missing hero is fine, a bad one isn't.
  • For Mac/iOS apps: prefer the App Store hero or developer-site screenshot. For physical products: prefer a clean studio shot or lifestyle photo without overlay copy. For travel destinations: prefer a Wikimedia Commons / Wikipedia image (free-to-use only). For text-only finds (quotes, dad jokes, essays): no media expected — skip.
  • Fetch strategy: curl -sL --max-time 25 -A "Mozilla/5.0 (...Safari...)" "<image-url>" -o <path>. WebFetch is for HTML, not binaries.

Log image-fetch failures (404, 403, marketing-only) as a one-line note in the capture-run section of daily-finds.log.md so we can revisit broken media-source patterns later.

4. Score and shortlist

After all finds are written, rank the day's captures and mark the shortlist — the up-to-a-dozen finds the rest of the pipeline should act on.

  • Score each of today's finds on: delight (would the audience light up), specificity of virtue (does the body name something concrete), media (clean hero present), and variety (the shortlist should not be twelve variations of one topic — spread across topics when quality allows).
  • Set shortlist: true in the frontmatter of the top finds. Aim for 612 on a normal day; fewer on a thin day. Never pad — a 4-item shortlist beats a 12-item one with filler.
  • Record the shortlist in the log, ranked, with a one-line rationale each. Note the top 13 as review candidates (strong media + strong story) — /build-review (or the pipeline) picks from these.

Amazon affiliate lookup

For every shortlisted physical product (tools, gifts, clothing, kitchen, EDC — not apps, not travel, not quotes/jokes/web pages):

  • Check whether the exact product is sold on Amazon: WebSearch site:amazon.com "<maker> <product name>", or curl the Amazon search page.
  • Only when the hit is unambiguously the same product (same maker, same model — not a lookalike, not a marketplace knockoff), add amazonLink: https://www.amazon.com/dp/<ASIN> to the find's frontmatter. Use the canonical /dp/<ASIN> form with no query parameters — the site's affiliate layer (src/lib/affiliate.ts) appends the tracking ID, badge, and disclosure at render time.
  • When in doubt, omit. A wrong affiliate link is worse than none. The site's focus is interesting items, not monetizable ones — this is a bonus, not a filter.
  • Non-shortlisted physical finds may get the same treatment when the match is trivially confident; don't burn time on them otherwise.

5. Nominate new sources

Watch for new sources organically and via search. No cap on nominees per run.

  • From inline references in source posts. When a post on a known source credits or links out to another publication as where they originally discovered the thing, capture that publication as a candidate source. Trigger phrases: "via X", "first seen on Y", "spotted by Z", "h/t X", "originally posted on Y", or any byline / sidebar link pointing to a different domain that itself looks like a curated feed. Cool Tools, Recomendo, Kottke, and Daring Fireball especially tend to credit their finds.
  • From general observation. When a publication is mentioned in a way that suggests it'd fit the brief (curated, taste-driven, focused on delightful or unusual items), nominate it.
  • From targeted search. If the run produced few or no organic candidates, run one WebSearch for "best <topic> newsletter" or "<topic> curator blog".

Append every nominee to candidate-sources.md under today's date heading. For each: name, URL, a one-line case for adding, and how it was surfaced.

Adding new sources to sources.json remains a user decision — never auto-add.

6. Source maintenance (mechanical edits — apply, don't recommend)

This skill has authority over mechanical sources.json hygiene. Past runs accumulated "overdue" recommendations nobody executed; that pattern is over. Apply these directly during the run:

  • Hard-blocked source (Cloudflare challenge, empty 403s, dead DNS) for the 3rd consecutive run: before skipping, probe for a feed (<link rel="alternate"> on the homepage, or common paths /feed, /rss.xml, /atom.xml, /index.xml). A working feed rescues the source — set fetch: "feed" + feedUrl. Otherwise set fetch: "skip" with a dated skipReason.
  • Dormant source (live but no new content across 3+ runs): demote cadence to as-needed; if the newest content is over a year old, fetch: "skip" with reason "dormant since ".
  • Better fetch path discovered (feed URL, Shopify /collections/new/products.json, article-level URL pattern that bypasses an index-level block): record it in fetch/feedUrl/fetchUrl immediately.
  • Quarterly re-probe: if any fetch: "skip" entry has a skipReason dated 90+ days ago, re-test it this run; blocks get lifted. Remove the skip when the source is back.
  • Update the top-level updated field when you touch the file.

Every mechanical change gets one line in the log's maintenance section. Only new sources need the user (step 5).

Note on Reddit: anonymous JSON/RSS endpoints have been blocked since ~June 2026. If REDDIT_CLIENT_ID / REDDIT_CLIENT_SECRET are available in the environment (or .env), obtain an app-only OAuth token (https://www.reddit.com/api/v1/access_token, grant_type=client_credentials) and fetch https://oauth.reddit.com/r/<sub>/top?t=week with it. If no credentials exist, log the Reddit sources as blocked-pending-oauth and move on — don't retry anonymous endpoints every run.

7. Update the log

Append to daily-finds.log.md:

## YYYY-MM-DD — capture run

Sources scanned: <N> total — <hits> hits, <empty> empty, <blocked> blocked, <skipped> skipped, <cadence-skipped> cadence-skipped.
Productive sources: <comma-separated list of sources that produced at least one written find>.

Captured finds:
- <slug> — <name> — source: <source>
- ...

Shortlist (<N>, ranked):
1. <slug> — <one-line rationale> [review candidate]
2. <slug> — <one-line rationale>
...

Amazon links added: <N> (<slug>, <slug>, ...) — or "none".

Source maintenance:
- <one line per sources.json change> — or "none".

New source nominees: <count> (see candidate-sources.md).

8. Report to the user

Short digest in chat (or, when running as part of /daily-pipeline, feed this into the pipeline digest):

Captured <N> finds across <M> productive sources; shortlisted <K>.
Review candidates: <slug>, <slug>.
Amazon links: <N>. Source maintenance: <N> changes. New nominees: <count>.
Blocked: <list or none>.

Notes

  • "Why it fits" / find descriptions should name a specific virtue. Bad: "great design". Good: "magnetic connector means it never strains the cable when a foot catches it".
  • Travel destinations relax the daily-use criterion — a place qualifies if a visitor would remember it years later.
  • If a source's homepage is too noisy, prefer adding a feedUrl/fetchUrl to sources.json rather than working around it inside the skill.
  • Never invent slugs that collide with existing finds or reviews. If a name would produce a colliding slug, append a year or distinguishing word.
  • Source attribution must be exact — the source field in each find file must match a name in sources.json so the /sources page cross-reference works.
  • For large sweeps, fan out: scanner subagents per source cluster → central dedup/bar/shortlist pass → writer subagents for files + heroes. Keep the shortlist ranking in the main context — it's the editorial judgment call of the run.