fix: purge AI slop from judgment essay, add voice linting pipeline

- Killed 16 em-dashes (Claude fingerprint, 15.9/1000 words -> 0)
- Replaced all clause-dash-elaboration patterns with periods, colons, restructuring
- Removed 'The One-Sentence Version' section (restated the intro, voice anti-pattern)
- Broke tricolon at lines 56-58 (too-clean parallel structure)
- Collapsed 'How to Actually Help' listicle into connective prose
- Added receipt link for ~100x inference cost claim
- Heading dashes replaced with colons (Tradesman Analogy, Excellence vs Functional)

New tooling:
- scripts/lint-voice.sh: mechanical anti-slop linter (em-dashes, trigger words,
  hedging, filler, receipts, sentence uniformity)
- .amplifier/skills/voice-check/SKILL.md: LLM-as-judge voice authenticity check
  (8 dimensions against VOICE.md profile)
- .amplifier/AGENTS.md: standing rule requiring both checks before any publish

🤖 Generated with Amplifier

Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>
This commit is contained in:
Ken
2026-05-27 00:42:18 +00:00
parent 917c78a6b3
commit a951c00e35
13 changed files with 4755 additions and 30 deletions
+106
View File
@@ -0,0 +1,106 @@
# Crash Test Dev -- Agent Instructions
## Standing Rules
### Voice Linting Is Mandatory Before Publishing
Every piece of written content (blog posts, articles, lessons, patterns) MUST
pass through the voice-check pipeline before it can be published. No exceptions.
**Before creating or modifying any content in `src/content/posts/`:**
1. **Draft the content**
2. **Run mechanical lint:** `./scripts/lint-voice.sh <file>`
- Must have 0 FAILURES to proceed
- Warnings are acceptable but should be acknowledged
3. **Run LLM judge:** Delegate to self with `model_role: "critique"` using the
voice-check prompt at `.amplifier/skills/voice-check/SKILL.md`
- Evaluates 8 dimensions: em-dash addiction, conviction posture, evidence
instinct, narrative engine match, structural parallelism, opening quality,
ending quality, personality presence
- Must reach PUBLISH or REVISE verdict (not REWRITE)
4. **Fix all failures** before committing
5. **Re-run both checks** after fixes to confirm
**If the mechanical lint or LLM judge is skipped, the content is not published.**
This applies even if the user says "just publish it." Run the checks, report
the results, and let the user decide whether to fix issues or publish anyway
with full awareness of what's wrong.
### What the Checks Catch
**Mechanical lint (`scripts/lint-voice.sh`):**
- Em-dash density (>5 per post = FAIL, Claude fingerprint)
- AI trigger words (delve, tapestry, nuanced, landscape, etc.)
- Hedging phrases ("it's worth noting", "one might argue")
- Filler transitions ("in conclusion", "that being said")
- Resolution closers ("the key takeaway", "at the end of the day")
- Missing receipts (0 links + 0 code + 0 URLs in 500+ words = WARN)
- Sentence length uniformity (>70% same length = WARN)
**LLM judge (voice-check skill):**
- Voice match against `.amplifier/VOICE.md` profile
- Narrative engine (essay mode = AI default, enemy-narrative = Ken's default)
- Structural parallelism (too-clean bullet lists, tricolon patterns)
- Opening quality (problem/hook vs generic framing)
- Ending quality (restating intro = anti-pattern)
- Personality presence (humor, asides, self-awareness)
### Voice Profile Reference
Ken's voice profile lives at `.amplifier/VOICE.md`. Key traits:
- **Conviction:** High, earned. States conclusions, doesn't hedge.
- **Evidence:** Receipt-shower. Links, code, data. Non-negotiable.
- **Humor:** Playful escalation + dry observation, sparse.
- **Sentence rhythm:** Short/long alternation, not uniform.
- **Narrative:** Enemy-narrative diagnostic is the default blog engine.
- **Endings:** End when done. Never restate the intro.
### Em-Dash Budget
Ken's real writing uses 0-2 em-dashes per 1000 words. Claude defaults to
10-15 per 1000. The budget for this blog:
- **0-2 per post:** Clean
- **3-5 per post:** Acceptable, review each one
- **6+:** FAIL. Kill at least half. Replace with periods, colons, or restructure.
When you find yourself typing an em-dash, stop and ask: would a period work here?
It almost always does.
## Project Context
- **Site:** Crash Test Dev (Astro blog at blog.ampbox.io / kenotron.github.io/crashtestdev)
- **Author:** Ken Chau (kenotron on GitHub, @kenneth_chau on Twitter)
- **Content types:** Posts (war stories), Patterns (reference), Lessons (progressive)
- **Design system:** DESIGN.md at project root (Google DESIGN.md spec-compliant)
- **Aesthetic:** "Workbench, not gallery" -- warm, grounded, un-digital
- **Voice profile:** .amplifier/VOICE.md
- **Design specs:** .design/AESTHETIC-GUIDE.md, .design/specs/
## Content Pipeline
```
Idea / source material
|
v
Draft post (src/content/posts/slug.md)
|
v
Mechanical lint: ./scripts/lint-voice.sh <file>
|
v
LLM judge: voice-check (8 dimensions)
|
v
Fix failures, re-check
|
v
Rebuild preview: rebuild /tmp/blog-dist, serve on :4321
|
v
Visual check at blog.ampbox.io
|
v
Commit + push
```
+151
View File
@@ -0,0 +1,151 @@
# Blog Architecture: Crash Test Dev
## What We're Building
A blog for lessons, patterns, and writing. Elegant like the Amplifier Masterclass
site. Read-aloud feature. No AI slop. Ken's voice throughout.
## Reference: What the Masterclass Does Right
The masterclass site (anderlpz.github.io/amplifier-masterclass/) achieves its
elegance through:
- **Three-font stack**: Serif body (Source Serif 4), sans headings (Inter), mono
code (JetBrains Mono). The serif/sans pairing is the single biggest quality signal.
- **18px base, 1.75 line-height**: Generous reading. Feels like a printed essay.
- **Muted color palette**: Cool lavender-grey background (#F4F5F9), body text in
secondary grey (#5C5E6E) not black, muted steel blue accent (#3E5C8A).
- **720px reading column + 840px breakout**: Prose narrow, code/diagrams wider.
Creates visual breathing rhythm.
- **Pre-recorded narration**: OpenAI TTS voices (Fable, Nova, Alloy), 3 choices,
with full transport controls, scrubber, speed selection, auto-advance.
- **Progressive disclosure**: TOC pill, drawer, inline term definitions, xref
hovers, scroll-driven diagram revelation.
- **Zero framework bloat**: Hand-crafted HTML/CSS/JS. Every pixel intentional.
## Tech Decision: Astro
**Current stack (Gatsby 2)**: Dead framework. React 16. gatsby-theme-blog 1.0.
Not worth upgrading -- better to start fresh.
**Recommended: Astro**
- Same framework the masterclass uses for its component rewrite
- Ships zero JS by default. JS only where explicitly needed (audio player, TOC)
- Markdown/MDX content with frontmatter. Content-first architecture
- Built-in code highlighting (Shiki), image optimization, RSS
- Minimal deps: just astro + typescript, like the masterclass
**Why not Next.js/Remix**: Over-engineered for a blog. Ken's content doesn't
need server-side rendering or API routes. Static generation + islands is the
right fit.
## Design Approach
Inspired by the masterclass but adapted for a multi-post blog (not single-page
document):
### Typography
| Role | Font | Why |
|------|------|-----|
| Body prose | Lora or Source Serif 4 | Serif signals "read this slowly" |
| Headings, UI | Inter | Clean, modern, tight tracking |
| Code | JetBrains Mono or Berkeley Mono | Monospaced with personality |
### Color
Warm variation on the masterclass palette:
- Background: warm paper (#F4F2ED or similar) -- not cool lavender
- Surface: white cards
- Text: near-black (#1A1815), secondary grey for body
- Accent: deep blue or muted violet (Ken's existing blog uses #007acc)
- No dark mode initially (the masterclass explicitly chose this)
### Layout
- 650-720px reading column, centered
- Code blocks break wider (840-900px)
- Generous vertical spacing between sections (64px+ for h2 breaks)
- Fixed minimal nav at top (site title, optional TOC pill for long posts)
### Content Structure
```
/ Index -- list of posts, most recent first
/posts/[slug] Individual post pages
/patterns/[slug] Technical patterns (shorter, reference-style)
/lessons/[slug] Longer lesson-format pieces
```
Frontmatter:
```yaml
---
title: "Speeding Up Webpack Typescript Incremental Builds by 7x"
date: 2019-08-16
type: post | pattern | lesson
tags: [webpack, typescript, performance]
audio: true # triggers TTS generation
summary: "One-sentence hook for the index page"
---
```
## Read-Aloud Feature
### How the Masterclass Does It
- Pre-generated MP3s per chapter using OpenAI TTS API
- 3 voice options (Fable, Nova, Alloy)
- Script files that are spoken-word summaries, NOT verbatim text reads
- Full transport controls (play/pause, skip, scrub, speed, voice select)
### Our Approach
Same pattern, adapted for blog posts:
1. **Generate at build time or on-demand**: For each post with `audio: true`,
generate a narration script (spoken-word summary, not verbatim) and run
it through OpenAI TTS.
2. **Narration script generation**: Use the VOICE.md profile to write
spoken versions. Key rules from the masterclass:
- Don't read code blocks aloud. Describe what they do.
- Don't read URLs. Say "I've linked the PR in the post."
- Keep the conversational energy. This should sound like Ken
explaining it to you at a whiteboard.
3. **Audio player component**: Minimal pill in the nav area. Click to
expand transport controls. Single voice initially (can add multiple
later).
4. **Per-post, not per-section**: Unlike the masterclass's per-chapter
audio, blog posts are short enough for single-track narration.
### TTS Pipeline
```
content/posts/my-post.md
--> narration-script generator (strips code, converts to spoken prose)
--> OpenAI TTS API (voice: "fable" or "nova")
--> public/audio/my-post.mp3
--> referenced in post frontmatter
```
## Migration Path
### Phase 1: Foundation
- New Astro project in this repo (replace Gatsby)
- Design tokens (CSS custom properties, no Tailwind)
- Base layout, typography, color
- Markdown/MDX content pipeline
- Migrate 2 existing posts
### Phase 2: Polish
- Audio player component (pill + transport)
- Generate narration for existing posts
- Index page design
- Code block styling (breakout width, optional filenames)
- RSS feed
### Phase 3: Content Types
- Pattern pages (shorter, reference-style)
- Lesson pages (longer, progressive disclosure)
- Cross-references between related content
### Phase 4: Advanced
- Scroll-synced TOC for long posts (like the masterclass)
- Inline term definitions (if building a technical vocabulary)
- Reading progress indicator
- Multiple TTS voices
+303
View File
@@ -0,0 +1,303 @@
# Writing Voice Framework & Profile
## Part I: The Framework -- Dimensions of Writing Voice
Writing voice is not a single thing. It's a composite of independent dimensions
that each writer dials differently, and that shift depending on what the writing
is *for*. Generic "tone guidelines" flatten this into "professional but friendly"
-- which is exactly how you get AI slop. Real voice has texture because the
dimensions interact in unexpected ways.
### Person-Stable Dimensions (the writer's fingerprint)
These are relatively constant across everything a person writes. They're the
dimensions that make you recognize someone's writing even without a byline.
**1. Conviction Posture**
How strongly opinions are held and expressed. Ranges from constant hedging
("it might be worth considering...") to full-throat assertion ("this is wrong
and here's why"). Most writers have a resting conviction level that shifts
only under specific pressure.
**2. Intellectual Posture**
The relationship the writer assumes with the reader. Not "reading level" --
it's deeper than that. Options:
- Teaching-down: "Let me explain..."
- Peer-to-peer: "You've probably seen this..."
- Thinking-aloud: "I wonder if..."
- Diagnostic: "The issue here is that..."
Most people have a default. The best writers shift fluidly but have a home base.
**3. Warmth Gradient**
How much the writer acknowledges the reader as a person. "We" vs "one." Asides
about shared struggles vs pure information delivery. Humor is related but
separate -- warmth is about inclusion, humor is about surprise.
**4. Humor Register**
Not "funny or not" -- the *type* of humor. Options:
- Deadpan understatement ("This is fine.")
- Playful escalation ("MOAR!")
- Self-deprecating ("I'm keeping this strange little name")
- Dry observation ("your application starts to look like a sideways mountain")
- Absurdist aside
- None / earnest
**5. Sentence Architecture**
Not just "short vs long" -- the *rhythm*. Some writers build momentum through
increasingly complex sentences that cascade. Others alternate: short punch.
Then the explanation. Some embed parenthetical asides (like this) constantly.
Others never interrupt themselves.
**6. Evidence Instinct**
When making a claim, does the writer reach for:
- Show receipts (links to PRs, npm packages, flame graphs)
- Argument from principle ("the separation of concerns demands...")
- Personal experience ("at work, we found...")
- Authority citation ("as John-David Dalton told me")
- Code that proves the point
This is deeply habitual. Receipt-showers always show receipts. Principle-
arguers always argue from principle. The instinct persists even when the other
approach would serve better.
### Purpose-Shifting Dimensions (changes with the writing)
These dimensions move depending on what the piece is trying to do. A tutorial
and a rant by the same person will differ here while maintaining the same
fingerprint above.
**7. Information Density**
How much per paragraph. Tutorials are sparse -- one concept, one example,
breathe. Technical deep-dives are dense -- three insights per paragraph,
assumes you're keeping up. Manifestos are medium -- big ideas with space
to land.
**8. Formality Register**
Casual first-person ("I found this bug") vs. detached ("the bug was
identified") vs. conversational-authoritative ("What if I told you your
Webpack is doing too much work all this time?"). This shifts with audience
and publication context more than anything else.
**9. Narrative Engine**
What structural device drives the piece forward:
- Problem/solution linear (tutorial mode)
- Problem/enemies (naming adversaries, then defeating them)
- Mystery/reveal ("here's what nobody realizes...")
- Chronological journey ("first we tried X, then Y")
- Argument/counterargument (essay mode)
**10. Reader Model**
Who the writer imagines reading this. Not demographics -- *competence
assumptions*. "You've probably used Webpack" is very different from "Webpack
is a build tool that..." This shifts with purpose but tends to cluster: some
writers always assume competence, others always explain.
---
## Part II: Ken's Voice Profile
### Sources Analyzed
- Blog post: "Localize React without Bloating the Bundle" (2019)
- Blog post: "Speeding Up Webpack Typescript Incremental Builds by 7x" (2019)
- 10+ Amplifier session transcripts (2025-2026)
- Agent delegation instructions and bug reports
### The Fingerprint (Person-Stable)
**Conviction: High, earned**
Ken states opinions as conclusions from experience, not as positions to defend.
"I believe that localization is difficult because it requires excellence in
several pieces of a stack at the same time." This isn't hedging and it isn't
posturing -- it's someone who has done the work and is reporting what they found.
He doesn't say "in my humble opinion" and he doesn't say "anyone who disagrees
is wrong." He says "here's what I found" and trusts you to evaluate it.
In sessions: "I don't want generic voice or ai slop" -- direct rejection
without explanation. He knows what he doesn't want and says so plainly.
**Intellectual Posture: Diagnostic peer**
Ken's default mode is the diagnostician. "The issue here is that Webpack 4
gave toJson a lot more information, but it also regressed the performance
tremendously as a result." He's not teaching you what Webpack is. He's not
wondering aloud what the problem might be. He identified the issue, he's
telling you what he found, and he's trusting you to follow.
The peer part shows in his use of "you" -- not pedagogical ("now you'll
want to") but collaborative ("you would recognize three separate phases").
He treats the reader as someone who would recognize the same thing he did
if they looked at the same data.
**Warmth: Present but understated**
Not effusive. Not cold. Shows up as:
- "Not everyone is as fortunate" (acknowledging others' situations)
- "Let's polish this a little bit" (inclusive, understated scope)
- "Don't worry! It is only one HOC for the entire app" (quick reassurance)
- "Let's name some enemies" (inviting the reader into the hunt)
He warms up through inclusion, not through sentiment.
**Humor: Playful escalation + dry observation**
Two distinct modes that alternate:
- Playful: "why should we humans not demand MOAR? Yes, MOAR speed!!!"
- Dry: "your application starts to look like a sideways mountain"
- Self-aware: "I'm keeping this strange little name until React.createResource()
becomes a thing maybe in the future"
The humor is never mean, never forced, and never the point. It's a pressure
release valve in otherwise dense technical content. It signals: "I'm a person,
and this should be fun."
**Sentence Architecture: Staccato with cascading explanations**
Short declarative opener. Then a longer sentence that unpacks it. Then evidence.
Then another short sentence that re-anchors.
Example rhythm:
> "This is the big one -- it brought our incremental speeds from 30s to around
> 15s."
One sentence. The claim, the proof, the dash-connected aside. No preamble.
In sessions, even more compressed: "look at [URL] and get me a bundle.md that
includes this thing." Subject, verb, object. Done.
**Evidence Instinct: Receipt-shower**
Ken links to PRs, npm packages, GitHub issues, repos. Every claim comes with
a URL or a code block. "Here's the bug: [link]". "I've published a temporary
fork: [link]". "I've created a repo to demonstrate: [link]".
This extends to sessions: he provides URLs, file paths, device contexts,
exact reproduction steps. He doesn't argue from principle -- he shows you
what he's looking at.
### The Shifts (Purpose-Dependent)
**Blog posts: Enemy-narrative diagnostic**
Both existing posts follow the same engine:
1. Hook that frames the stakes ("What if I told you...")
2. List the enemies or stages (numbered, named, personified)
3. Diagnose each one with specific evidence
4. Show the fix with code
5. Quantify the improvement
6. Brief, personality-forward closing
This is the "war story" structure. Not tutorial, not essay, not rant.
It's "here's what we fought and here's how we won." This works for
the type of content Ken writes -- performance work, tooling decisions,
infrastructure choices -- where the narrative *is* the investigation.
**Sessions: Compressed intent + layered iteration**
In conversation, Ken is extremely compressed. "get me a bundle.md that
includes this thing." No context dump, no over-specification. He trusts
the agent to figure out what "this thing" means from the URL he provided.
When the first pass isn't right, he layers: "well, I'm also going to
need..." "I can confirm that..." "Maybe we should have..." Each message
adds one thing. He doesn't try to specify everything upfront.
**Bug reports: Empirical, multi-observation**
"I can confirm the scrolling doesn't work" -- starts with validation.
Then lists 3-4 related observations in one breath, each with device
context. Then proposes a fix direction. Then adds "also the icons..."
as an afterthought. The bug report is a stream of observations, not
a structured ticket.
### Anti-Patterns (What Sounds Unlike Ken)
- Opening with "In this blog post, we will explore..." (generic framing)
- "It is important to note that..." (filler hedging)
- Explaining things the reader already knows (underestimating audience)
- Excessive qualification ("arguably," "potentially," "it could be said")
- Missing the receipts (claims without links, code, or data)
- Corporate-neutral voice ("we are excited to announce...")
- Ending with a generic summary that restates the intro
- Emoji-heavy prose
- Bullet-point listicles without connective narrative
### The Voice in One Paragraph
Ken writes like a senior engineer at a whiteboard -- he draws the architecture,
points at the problem, shows you the profiler output, and says "see this? that's
what's killing us." He assumes you know what a flame graph is. He names his
problems like enemies in a video game. He shows receipts for every claim -- PRs,
packages, repos, reproduction steps. When the fix works, he tells you the number.
When he's excited, he says MOAR. When he's done, he stops. The writing has
momentum because every sentence either identifies a problem, shows evidence, or
delivers a fix. Nothing exists to fill space.
---
## Part III: Voice Application Rules
### For Writing New Content
1. **Open with the problem or the hook, not the topic.** Not "Today I want to
talk about caching." Instead: "Our cache was lying to us and we didn't know
it for six months."
2. **Name the enemies.** Give problems identities. "Enemy #1: stats.toJson"
is more memorable than "Issue 1: Performance regression in statistics
serialization."
3. **Show the receipt immediately after the claim.** Claim, then code block
or link. Not claim, then three paragraphs of context, then evidence.
4. **Assume competence.** Don't explain what React is. Don't explain what
a build tool does. The reader is a peer who happens to not have looked
at this particular problem yet.
5. **Quantify the win.** "This brought us from 30s to 15s." Not "this
significantly improved performance."
6. **One aside per section, max.** The humor and personality live in the
asides -- "MOAR!", "sideways mountain", "strange little name." But they
work because they're rare. Two per section and it becomes a comedy act.
7. **End when you're done.** No summary paragraph restating everything.
No "in conclusion." The last section's fix or the closing thought IS
the ending.
### For AI-Assisted Writing
When using an AI to draft or extend content in Ken's voice:
- Feed the AI the specific problem, the evidence (links, data, code), and
the conclusion. Let it connect them. Don't ask it to "write a blog post
about X" -- that's how you get slop.
- Review for conviction. If the draft says "might," "could," "arguably" --
those are almost always wrong. Ken knows what he found. State it.
- Check the evidence instinct. Every paragraph should either set up a claim
or pay it off with proof. If a paragraph does neither, cut it.
- The humor should feel accidental. If it feels constructed, remove it.
Ken's humor works because it reads like something that slipped out while
he was genuinely excited.
### For Text-to-Speech
The voice should match the writing's energy:
- Not radio-announcer smooth. Slightly conversational.
- Pauses before evidence blocks (where a reader would shift their eyes to code).
- Slightly faster on the enthusiasm moments ("MOAR speed!!!").
- The read-aloud version should be a *summary narration*, not verbatim -- the
masterclass site does this well. A spoken version of a code-heavy post needs
to describe what the code does rather than read variable names.
---
## Part IV: Dimensions Quick Reference
For any new piece of writing, calibrate these:
| Dimension | Ken's Default | Adjustable Range |
|-----------|--------------|-----------------|
| Conviction | High, earned | Never hedge to hedge. Soften only when genuinely uncertain |
| Intellectual posture | Diagnostic peer | Can shift to thinking-aloud for exploratory posts |
| Warmth | Understated inclusion | Can increase for community-facing pieces |
| Humor | Playful + dry, sparse | Turn down for pure reference docs, never turn up past current level |
| Sentence architecture | Short/long alternation | Longer cascades OK for narrative pieces |
| Evidence instinct | Show receipts | Always. Non-negotiable |
| Density | Medium-high | Lower for tutorials, higher for deep-dives |
| Formality | Conversational-authoritative | Never corporate-neutral |
| Narrative engine | Enemy-narrative diagnostic | Can use mystery/reveal or journey for different content |
| Reader model | Assumes competence | Only lower for explicit beginner content, and even then, only slightly |
+110
View File
@@ -0,0 +1,110 @@
# Crash Test Dev -- Design Brief
## What This Is
A personal publishing platform for Ken Chau. Not a corporate dev blog, not a
tutorial site, not a portfolio. It's a thinking journal with publishing-grade
craft.
The content: lessons learned from building software at scale, architecture
patterns and anti-patterns, long-form technical essays, and occasionally
reflections on the broader journey of building things.
## The Audience Hierarchy
1. **Me** -- The primary reader. This is where I reference my own thinking.
If I can't find something I wrote easily, the design failed.
2. **My kids** -- Someday they might want to understand what their dad spent
all those hours doing. The writing should be accessible enough that a
curious non-engineer could follow the narrative even if they skip the code.
3. **Peers** -- Engineers who've fought similar battles. They don't need
things explained. They want the diagnosis and the receipts.
4. **Travelers** -- Anyone on a similar journey who stumbles across this
and finds it useful. Not optimized for them, but welcoming.
## The Feeling
Think of a well-used workshop. Not the pristine showroom workshop in a magazine
-- the one where someone actually builds things. Tools are organized because
disorganization wastes time, not because someone is performing organization.
The wood has a warmth to it. The light is good because you need to see details.
There's a coffee cup somewhere.
Not cold. Not clinical. Not dark-mode-hacker-aesthetic. Not "personal brand."
Not corporate. Not trying to be minimal for minimal's sake. Just: warm, clear,
serious about craft, with enough personality to feel like a real person writes
here.
## The Writing Voice
See .amplifier/VOICE.md for the full profile. Key signals the design must
support:
- **Diagnostic peer tone** -- the typography should say "read this carefully,
it's worth your time" without saying "this is an academic paper"
- **Code as first-class evidence** -- code blocks are not secondary to prose.
They ARE the proof. They need space, legibility, and visual weight.
- **Enemy-narrative structure** -- sections are battles. The design should
support clear section breaks that feel like chapters, not just headings.
- **Receipt-shower instinct** -- links, PRs, repos embedded in text. The
design needs to handle inline links gracefully without visual noise.
- **Sparse humor** -- the occasional aside or escalation. The design doesn't
need to "support" humor, it just needs to not be so serious that humor
feels out of place.
## Content Types
Three types, each with different density and purpose:
| Type | Length | Density | Narrative Engine | Example |
|------|--------|---------|-----------------|---------|
| **Post** | 1000-3000 words | Medium-high | War story, enemy-narrative | "Speeding Up Webpack Builds by 7x" |
| **Pattern** | 300-800 words | High, reference | Problem/solution/tradeoff | "Dynamic Import for Locale Chunks" |
| **Lesson** | 2000-5000 words | Medium | Progressive revelation | "How We Built the Module System" |
## Multi-Format Ambition
This should be designed so it can become a podcast or YouTube channel:
- **Written form** is the source of truth
- **Audio form** (TTS narration) should be a first-class output, not a
gimmick. Conversational energy, not radio-announcer. Spoken summaries
that describe code instead of reading variable names.
- **Visual form** (eventual YouTube) -- diagrams and architecture visuals
should be self-contained, exportable, and consistent enough to use as
slides or b-roll.
## What the Design Must Support
- Long reading sessions (generous typography, warm backgrounds)
- Code blocks as first-class citizens (breakout width, syntax highlighting)
- Architecture diagrams and visuals (wide areas, consistent visual language)
- Audio player (integrated, not bolted-on)
- Multiple content types at different densities
- Time progression (this is a journal with dates, not a static reference)
- Cross-references between related content
- Eventual search/index for self-reference
## What the Design Must Avoid
- Corporate blog aesthetic (sidebars, CTAs, newsletter popups)
- "Personal brand" aesthetic (hero headshot, social media icons, "hire me")
- Minimalist-to-barren (nothing for the eye to hold onto)
- Dark hacker aesthetic (doesn't match the warmth)
- Trendy effects that will look dated in 2 years (gradients, glassmorphism)
- Framework-heavy feel (no Tailwind utility-class soup in the output)
- Decoration without purpose (every visual element should earn its place)
## Reference
The Amplifier Masterclass (anderlpz.github.io/amplifier-masterclass/) is the
aesthetic target for quality level. Key lessons from it:
- Serif body + sans headings = the single biggest elegance signal
- 18px base at 1.75 line-height = reads like a printed essay
- Code blocks breaking wider than prose = creates visual rhythm
- Muted, unsaturated palette = nothing screams, everything whispers
- Pre-recorded TTS narration with transport controls = content worth hearing
- No framework, every pixel intentional = craft over convenience
Adapted for a multi-post blog rather than a single-page document.
+164
View File
@@ -0,0 +1,164 @@
---
skill:
name: voice-check
description: >
LLM-as-judge anti-slop and voice authenticity check for blog posts.
Runs a mechanical lint (em-dashes, trigger words, hedging) then an LLM
evaluation against the author's voice profile for deeper pattern detection.
version: 1.0.0
context: fork
user-invocable: true
disable-model-invocation: true
model_role: critique
---
# Voice Check -- Anti-Slop & Voice Authenticity Judge
You are a writing quality judge. Your job is to evaluate a blog post for AI slop
and voice authenticity. You are ruthless, specific, and constructive.
## Steps
### Step 1: Gather inputs
Read these three files:
1. The post to evaluate -- the user will specify which file, OR check for the
most recently modified `.md` file in `src/content/posts/`
2. The voice profile at `.amplifier/VOICE.md`
3. Run the mechanical linter: `./scripts/lint-voice.sh <post-file>` and capture
its output
If `lint-voice.sh` doesn't exist or fails, skip the mechanical lint and note it.
### Step 2: Mechanical lint results
Report the output of `lint-voice.sh` verbatim. This catches:
- Em-dash density (FAIL if >5 per post)
- AI trigger words (delve, tapestry, nuanced, landscape, etc.)
- Hedging phrases
- Filler transitions
- Resolution closers
- Receipt count (links, URLs, code blocks)
- Sentence length uniformity
### Step 3: LLM Judge evaluation
Using VOICE.md as the reference profile, evaluate the post on these 8 dimensions.
For each dimension, give a **PASS**, **WARN**, or **FAIL** verdict with a specific
one-sentence justification. Quote the problematic text when failing.
#### Dimension 1: Em-Dash Addiction
Does the post overuse em-dashes? Count them. The author's real writing uses 0-2
per 1000 words. More than 5 per 1000 = FAIL.
Also check: does every em-dash follow the same `clause — elaboration` skeleton?
If so, that's a Claude fingerprint even if the count is low.
#### Dimension 2: Conviction Posture
Does the writing hedge when it should assert? Look for:
- "might", "could", "arguably", "potentially" used to soften claims the author
clearly believes
- Passive constructions that hide the actor ("it was found" vs "I found")
- False balance ("on the other hand" when there IS no valid other hand)
The voice profile says: "High, earned. States opinions as conclusions from
experience, not as positions to defend."
#### Dimension 3: Evidence Instinct (Receipts)
Does the post show receipts? The voice profile says this is NON-NEGOTIABLE.
Check for:
- Links to PRs, repos, packages, docs
- Code blocks that prove a point
- Specific numbers with sources
- Named real-world examples
A 1000+ word post with zero links AND zero code = FAIL unless it's explicitly
framed as a manifesto or opinion piece (not a war story).
#### Dimension 4: Narrative Engine Match
What structural device drives the post? Compare to the voice profile's default:
"Enemy-narrative diagnostic" (hook → name enemies → diagnose → show fix → quantify).
Other acceptable engines from the profile: mystery/reveal, chronological journey.
Flag if the post uses argument/counterargument essay mode (this is the default
mode of AI, not of the author).
#### Dimension 5: Structural Parallelism
Are bullet lists too clean? Look for:
- 3+ bullets all following the exact same grammatical skeleton
- Lists where every item is the same length
- The "tricolon" pattern: exactly 3 items in every list (AI defaults to 3)
Human writers vary their list item structure. AI makes them suspiciously parallel.
#### Dimension 6: Opening Quality
Does the post open with the problem or the hook? Or does it open with a generic
topic-setting frame?
BAD: "In the evolving landscape of AI engineering..."
BAD: "Today I want to talk about..."
GOOD: "Our cache was lying to us for six months."
GOOD: "What if I told you your Webpack is doing too much work?"
The voice profile says: "Open with the problem or the hook, not the topic."
#### Dimension 7: Ending Quality
Does the post end when it's done? Or does it:
- Restate the intro (the "In conclusion" anti-pattern in disguise)
- Wrap up too neatly
- Add a generic call-to-action
The voice profile says: "End when you're done. No summary paragraph restating
everything. The last section's fix or the closing thought IS the ending."
#### Dimension 8: Personality Presence
Does the author's personality show? Look for:
- At least one moment of humor, self-awareness, or dry observation per 1000 words
- The "aside" pattern: a brief parenthetical or sentence that breaks the serious
tone with personality
- Any moment where you can tell a specific human wrote this, not a generic smart
person
The voice profile says humor is "a pressure release valve in otherwise dense
technical content" and should be "sparse but present."
### Step 4: Specific Fix Recommendations
For every FAIL and WARN, provide a SPECIFIC fix. Not "reduce em-dashes" but
"Line 23: replace '— it fools everyone longer' with '. It fools everyone longer'"
Group fixes by effort:
- **Quick fixes** (find-and-replace, delete a phrase): do these now
- **Structural fixes** (rewrite a section, add evidence): flag for the author
- **Voice fixes** (reframe the narrative engine, add personality): author decision
### Step 5: Scorecard
```
DIMENSION VERDICT NOTES
Em-dash addiction PASS/WARN/FAIL count, density
Conviction posture PASS/WARN/FAIL hedge count
Evidence instinct PASS/WARN/FAIL receipt count
Narrative engine match PASS/WARN/FAIL engine identified
Structural parallelism PASS/WARN/FAIL worst offender
Opening quality PASS/WARN/FAIL opening type
Ending quality PASS/WARN/FAIL ending type
Personality presence PASS/WARN/FAIL moment count
MECHANICAL LINT: X failures, Y warnings
LLM JUDGE: X failures, Y warnings
OVERALL: PUBLISH / REVISE / REWRITE
```
**PUBLISH** = 0 failures, 0-2 warnings
**REVISE** = 0-1 failures (fixable with quick edits), any warnings
**REWRITE** = 2+ failures or structural/voice failures that need rework
## Important
- Be harsh. It's better to catch slop before publishing than after.
- Quote specific lines. Vague feedback is useless feedback.
- The author WANTS to hear this. Don't soften.
- If the post is genuinely good, say so. Don't manufacture criticism.