Files
unique/.claude/skills/daily-pipeline/SKILL.md
T

102 lines
8.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
name: daily-pipeline
description: The full unattended daily run for unique.rzen.dev — capture (daily-finds) → bundle (build-bundle auto) → graduate reviews (build-review auto) → copy-edit pass (EDITORIAL.md) → set the pick of the day → build, commit, and push — ending with a digest. Use when the user runs /daily-pipeline, asks to "run the pipeline", "do the daily run", or when a scheduled/headless session needs the whole chain.
disable-model-invocation: true
---
# daily-pipeline
One command, whole day: everything from source sweep to a deployable commit, no confirmation gates. Each stage is an existing skill run in its autonomous mode — this skill is just the conductor plus the commit/digest discipline around it.
Invoke from inside the `unique.rzen.dev` repo. Requires a clean-ish working tree (uncommitted changes unrelated to the pipeline should be left untouched — stage only what each step produced).
## The chain
### 0. Preflight
- `git status` — note any pre-existing dirty files; never stage or commit them.
- Read the tail of `daily-finds.log.md` — when was the last capture run, the last weekly catch, the last cluster run.
- If today's capture run already happened (log has a `YYYY-MM-DD — capture run` entry for today), skip to step 2 rather than double-capturing.
### 1. Capture — run `daily-finds`
Follow `.claude/skills/daily-finds/SKILL.md` in full (scan → filter → write → shortlist + Amazon lookup → nominate → source maintenance → log). It runs unattended by design.
**Commit** (matching repo conventions):
`content: YYYY-MM-DD capture run — <N> finds across <M> productive sources`
Stage: the new find folders, `daily-finds.log.md`, `candidate-sources.md`, and `sources.json` if maintenance touched it.
### 2. Bundle — run `build-bundle` in auto mode
- Default: one themed bundle drawn from the unbundled shortlist pool (auto mode picks the strongest cluster itself). If the day's shortlist supports no honest theme, or no cluster meets the hero floor (≥2 items with hero images, aim for ~4 — see build-bundle), skip — don't force one; note the held-back theme in the digest.
- **Weekly catch check**: if no "week's catch" bundle exists for the trailing 7 days and unbundled shortlisted finds are accumulating, also run `build-bundle weekly`.
- **Backlog check**: if the unbundled pool has grown past ~25 shortlisted finds, run `cluster-bundles` in auto mode instead of a single bundle this run.
**Commit**: `site: bundle — <title>` (or `site: bundles — <t1>, <t2>` / `site: cluster run — <N> bundles`).
### 3. Reviews — run `build-review` in auto mode
- Take the capture run's **review candidates** (the top of the shortlist, marked in the log). Graduate **several per run — how many is your judgment call** (typically 24). Quality over cadence still rules: every graduation must clear the bar on its own, and zero is fine on a thin day. Prefer candidates with strong media and a real story; the fact-check step is mandatory.
- If today's capture was thin but a prior day's log lists ungraduated review candidates, those are fair game.
**Commit per review or combined**: `site: review — <Name> (graduates from find)` / `site: reviews — <A>, <B> (graduate from finds)`.
### 4. Copy edit — fresh-eyes pass over the day's new prose
Enforce `EDITORIAL.md` (the voice charter: concise, to the point, inspiring delight) on everything stages 13 wrote. The point is fresh eyes — the author of a piece is the worst person to cut it — so run this as a **subagent** (sonnet) that did not write the copy:
- Scope: find bodies, bundle blurb/intro, review bodies, subtitles and descriptions created or modified this run. Nothing older.
- The subagent gets `EDITORIAL.md` plus the file list, and edits prose only — never facts, names, prices, links, claims, or structural frontmatter (wording of `subtitle`/`description`/`blurb` is fair game). Word budgets in the charter are the hard lines. Use the canonical brief in `TEAM.md` ("The copy editor's brief") verbatim, substituting the file list.
- Review the diff in the main session before committing; revert any edit that changed meaning or lost the delight it was supposed to sharpen.
**Commit** (only when something changed): `site: copy edit — <N> pieces tightened`.
### 5. Pick of the day
Make an explicit pick decision **every run** — the pick is a daily editorial call, not a side effect of publishing reviews:
- **The pick must be uncontroversial — it's the front page.** The homepage hero greets every visitor out of context, so keep it broadly, unmistakably benign. Never pick anything that could read as endorsing or depicting harm: weapons or anything that cuts, burns, or explodes; anything dangerous or injury-prone; how-to's for any of that; horror or disturbing media; or anything that could be taken as a call to negative action. (A knife is a bad pick.) Such items can still be finds and reviews — they just never get the hero. If your strongest candidate trips this, take the strongest one that doesn't, and note the swap in the digest.
- **No camping gear in the hero.** Camper trailers and other camping equipment never take the pick — they stay eligible as finds and (occasionally) reviews, just not the front page. If the strongest candidate is camping gear, take the strongest one that isn't. (Both hero rules restate `EDITORIAL.md` "Content rules" — the charter is the source of truth.)
- **Aim for a fresh pick every day** — a new pick of the day is itself a small daily contribution to delight (`EDITORIAL.md`, north star). Candidates, in order of preference: reviews graduated this run; then past reviews that have **never held the pick** (check the `pick of the day` entries in `daily-finds.log.md` / `git log --grep="pick of the day"`); then the rest of the pool.
- "Strongest" = best hero visual + broadest audience appeal; when torn, the one whose virtue is most immediately legible from the tile.
- New reviews usually win, but a weak new review must not displace a strong current hero — before holding for that reason, scan the never-picked pool for one that delights.
- Keeping the current pick is a valid outcome when nothing — new or never-picked — genuinely beats it, but it's a decision like any other.
- **Every pick decision gets a log entry — holds included.** Append `## YYYY-MM-DD — pick of the day: <slug>` (or `— pick of the day: held <slug>`) to `daily-finds.log.md` with the reasoning: what it beat and why, or why the incumbent kept the slot. The digest line alone is not a record — the digest is ephemeral; the log is the audit trail.
Write `src/data/pick.json``{"hero": "<review-slug>"}`.
**Commit** (every run): `site: pick of the day — <Name>` when the pick changed (include the log entry); when held, commit the log entry alone as `content: pick held — <Name>`.
### 6. Verify + push
- `npm run build` must pass (it will also have been run by the sub-skills; this is the final gate). If it fails, fix what the pipeline broke; never push a red build.
- `git push origin main`. If the push fails (auth, network), leave the commits local and flag it in the digest.
- Deployment is automatic downstream: in scheduled runs, a lab CI job (`publish-unique-daily`) redeploys unique.rzen.dev from `main` after this pipeline succeeds — nothing to do here, but it means whatever is on `origin/main` goes live.
### 7. Digest
End with a compact, human-readable digest — this is the only thing the user should *need* to read:
```
Daily pipeline — YYYY-MM-DD
Captured: <N> finds (<M> productive sources), shortlisted <K>
Bundle: "<title>" (<n> items) [+ week's catch / cluster run if run]
Reviews: <Name> (<slug>), <Name> (<slug>) — or none
Copy edit: <N> pieces tightened — or clean
Pick: <Name> — or held: <current> (<one-line why>)
Amazon: <n> links added
Sources: <n> maintenance changes; <n> new nominees awaiting vetting
Attention: <anything needing the user: rejected graduations, blocked sources,
failed push, nominee backlog> — or "nothing"
Pushed: yes/no (<commit range>)
```
## Ground rules
- **Never pause for input.** Every judgment call is yours; make it, log it, surface it in the digest. The user vetoes after the fact — that's the operating model.
- **Granular commits** in the repo's established message style (see `git log`), one per stage, so any stage is individually revertable.
- **Don't touch** pre-existing uncommitted changes, `src/` code, or `sources.json` beyond what daily-finds' maintenance step allows.
- **Degrade gracefully.** A stage that fails or yields nothing doesn't abort the chain — note it in the digest and continue (except a red `npm run build`, which blocks the push).
- Candidate-source vetting and adding new sources to `sources.json` stay with the user. If `candidate-sources.md` has 10+ unvetted nominees, nudge in the digest's Attention line.