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:
@@ -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
|
||||
```
|
||||
@@ -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
|
||||
@@ -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 |
|
||||
@@ -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.
|
||||
@@ -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.
|
||||
Reference in New Issue
Block a user