pipeline: EDITORIAL.md voice charter + fresh-eyes copy-edit stage
One written standard for every audience-facing word: concise, to the point, inspiring delight through specificity — with word budgets per copy type (reviews had drifted from a ~370-word median to 500-1000+). All writing skills now reference the charter, and daily-pipeline gains a stage-4 copy-edit pass: a subagent that didn't write the day's copy tightens it against the charter, prose only, diff reviewed before commit. Digest gains a copy-edit line. Claude-Session: https://claude.ai/code/session_01WZaczDJjL3xZ3u5spsN5AL
This commit is contained in:
@@ -104,7 +104,7 @@ items:
|
||||
---
|
||||
```
|
||||
|
||||
Body: a brief audience-facing intro paragraph (1–2 sentences max) — open with "Today's catch" or a close variant; name what links these finds; vary the wording day to day. **No** numbered candidates, no headings inside the body, no list items — the grid renders from `items[]`.
|
||||
Body: a brief audience-facing intro paragraph (1–2 sentences max, per `EDITORIAL.md`) — open with "Today's catch" or a close variant; name what links these finds; vary the wording day to day. **No** numbered candidates, no headings inside the body, no list items — the grid renders from `items[]`.
|
||||
|
||||
Example body:
|
||||
|
||||
|
||||
@@ -63,7 +63,7 @@ Take the find's 2-3 sentence body and expand it to a full review:
|
||||
- 3-5 paragraphs covering: what it is, the specific problem it solves, the concrete details that make it earn its place, and any honest limitations (surfaced by step 3).
|
||||
- Reference the hero asset inline where it helps (relative `./hero.<ext>`; use `astro:assets` `<Image>` for JPG sources — plain Markdown images have rendered small on JPGs).
|
||||
- Don't pad. If the find body is already complete, the review is just it + a blockquote summary + maybe one paragraph on context.
|
||||
- Match the voice of existing reviews under `src/content/reviews/` — informative, concise, no sales tone.
|
||||
- Write to `EDITORIAL.md` (the voice charter): concise, to the point, delight through specificity. Budget: **250–450 words, hard ceiling 600** — narrative subjects (travel, history, story-led pieces) may earn up to ~800 when the story itself is the delight. Budgets are ceilings, not targets.
|
||||
|
||||
Interactive mode: show the proposed body and wait. Autonomous mode: proceed.
|
||||
|
||||
|
||||
@@ -89,7 +89,7 @@ items:
|
||||
|
||||
Body rules (same as `build-bundle`):
|
||||
|
||||
- 1-2 sentence intro paragraph in a blockquote. No headings, no list items, no numbered candidates — the grid handles the items.
|
||||
- 1-2 sentence intro paragraph in a blockquote, per `EDITORIAL.md`. No headings, no list items, no numbered candidates — the grid handles the items.
|
||||
- Audience-facing language. Never write "today's pick", "candidates", "winners".
|
||||
- Vary the opening across the batch. With 4-7 bundles going out the same day, repeating "Today's catch" five times feels mechanical.
|
||||
|
||||
|
||||
@@ -60,7 +60,7 @@ For every survivor, write one file at `src/content/find/<year>/<month>/<slug>/in
|
||||
|
||||
- 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".
|
||||
- Body: 2-3 sentence note (40–90 words), written to `EDITORIAL.md` — concise, and delightful through specificity: 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.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
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) → 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.
|
||||
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
|
||||
---
|
||||
|
||||
@@ -41,7 +41,17 @@ Stage: the new find folders, `daily-finds.log.md`, `candidate-sources.md`, and `
|
||||
|
||||
**Commit per review or combined**: `site: review — <Name> (graduates from find)` / `site: reviews — <A>, <B> (graduate from finds)`.
|
||||
|
||||
### 4. Pick of the day
|
||||
### 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 1–3 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.
|
||||
- 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:
|
||||
|
||||
@@ -56,13 +66,13 @@ Write `src/data/pick.json` → `{"hero": "<review-slug>"}`.
|
||||
|
||||
**Commit** (only when the pick changed): `site: pick of the day — <Name>`.
|
||||
|
||||
### 5. Verify + push
|
||||
### 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.
|
||||
|
||||
### 6. Digest
|
||||
### 7. Digest
|
||||
|
||||
End with a compact, human-readable digest — this is the only thing the user should *need* to read:
|
||||
|
||||
@@ -72,6 +82,7 @@ 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
|
||||
|
||||
@@ -14,6 +14,7 @@ Unattended runs never pause for confirmation — they publish, log to `daily-fin
|
||||
|
||||
## Conventions that bite
|
||||
|
||||
- **`EDITORIAL.md` is the voice charter** — concise, to the point, inspiring delight (through specificity, never ad copy); word budgets per copy type. All audience-facing prose follows it; the pipeline runs a fresh-eyes copy-edit stage over each day's new copy.
|
||||
- **No tobacco or alcohol content** — hard editorial exclusion at every stage: never captured as finds, never selected into new bundles, never graduated to reviews. A few legacy alcohol finds (May–July 2026) stay published and keep their existing bundle spots, but they're ineligible for anything new.
|
||||
- Review heroes are auto-discovered from `src/content/reviews/<slug>/hero.<ext>` (`src/lib/hero.ts` glob) — name the file `hero.*`; no registration.
|
||||
- The homepage "pick of the day" is `src/data/pick.json` (`{"hero": "<review-slug>"}`); falls back to the latest review.
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
# Editorial voice charter
|
||||
|
||||
The standard for every audience-facing word on unique.rzen.dev — find bodies, review bodies, bundle blurbs and intros, subtitles, descriptions. Skills reference this file; the pipeline's copy-edit pass enforces it.
|
||||
|
||||
## The voice in one line
|
||||
|
||||
Concise, to the point, and above all **inspiring delight**.
|
||||
|
||||
## Principles
|
||||
|
||||
1. **Delight is specificity.** Name the exact detail that makes someone light up — the silicone bumper that survives concrete, the hinge that closes with a click you can feel. Generic praise ("great design", "beautifully made") is dead copy; if the sentence could describe a hundred products, cut it.
|
||||
2. **Lead with the virtue, not the category.** The reader learns *why it's wonderful* before *what shelf it sits on*.
|
||||
3. **Every sentence earns its place.** No throat-clearing openings ("In a world where…", "We've all been there"), no scene-setting preamble, no restating in the close what the lead already said. If a sentence can go without losing a fact or a smile, it goes.
|
||||
4. **No ad copy.** Never "game-changer", "must-have", "stunning", exclamation points, or any superlative a competitor's brochure could also print. Enthusiasm comes from detail, not volume.
|
||||
5. **Honest beats glossy.** Limitations stated plainly; corrections from fact-checking called out when they're interesting. Trust is the site's only currency.
|
||||
6. **The forward test.** Before publishing, ask: would a friend forward this to another friend with "look at this"? If not, find the detail that would make them — or cut deeper.
|
||||
|
||||
## Word budgets
|
||||
|
||||
| Copy | Budget |
|
||||
|---|---|
|
||||
| Find body | 40–90 words (2–3 sentences) |
|
||||
| Review body | 250–450 words; hard ceiling 600 |
|
||||
| Review — narrative subjects (travel, history, story-led) | up to ~800 when the story itself is the delight — it must earn every paragraph |
|
||||
| Bundle blurb | one sentence |
|
||||
| Bundle intro | 1–2 sentences |
|
||||
| Subtitle / description | one line, no trailing period needed |
|
||||
|
||||
Budgets are ceilings, not targets — a 250-word review that says everything beats a 450-word one that pads.
|
||||
|
||||
## For the copy editor
|
||||
|
||||
The copy-edit pass (daily-pipeline stage 4) edits **prose only**: tighten, sharpen, de-pad, enforce the budgets. Never change facts, names, prices, links, claims, or frontmatter beyond wording of `subtitle`/`description`/`blurb`. Never add a claim the author didn't make. When a piece is over budget, cut the weakest material — don't compress every sentence into mush. When in doubt between two cuts, keep the one that delights.
|
||||
Reference in New Issue
Block a user