
Ia Writing
- 4 installs
- 28 repo stars
- Updated August 5, 2026
- iliaal/whetstone
Edits and humanizes prose by removing AI vocabulary and structural tells, enforcing active voice and concrete specifics across copy, docs, and PRs.
About
Ia-writing rewrites and humanizes text for natural tone, killing AI patterns, false agency, and formatting tells. A developer uses it to write, edit, proofread, or strip AI language from prose.
- Kill-on-sight vocabulary and structural-tell lists
- Active voice, contractions, and named-actor rules
Ia Writing by the numbers
- 4 all-time installs (skills.sh)
- Ranked #1,241 of 1,879 Documentation skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
npx skills add https://github.com/iliaal/whetstone --skill ia-writingAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 4 |
|---|---|
| repo stars | ★ 28 |
| Last updated | August 5, 2026 |
| Repository | iliaal/whetstone ↗ |
What it does
Edits and humanizes prose by removing AI vocabulary and structural tells, enforcing active voice and concrete specifics across copy, docs, and PRs.
Files
Human Writing
Core Principles
- Active voice: "We shipped the fix" not "The fix was shipped"
- Name the actor: Every sentence needs a human subject doing something. Inanimate objects don't fix bugs, shift cultures, or tell us anything -- a person does.
- Specific over vague: "Cut reporting from 4 hours to 15 minutes" not "Save time"
- Simple words: "Use" not "utilize", "help" not "facilitate", "start" not "initiate"
- Positive form: Say what it is, not what it isn't -- "Ignore" not "Do not pay attention to"
- Confident: Cut "almost", "very", "really", "quite", "arguably", and all -ly adverbs
- Concrete: Name the thing, state the number, cite the source
- Omit needless words: "Because" not "due to the fact that"; "Now" not "at this point in time"; "Can" not "has the ability to"
- Use contractions: "don't", "won't", "it's", "they're" -- uncontracted forms are a major AI tell
- Put the reader in the room: "You" beats "People." Specifics beat abstractions. Avoid narrating from a distance.
AI Patterns -- Kill on Sight
Models reproduce sentence structures more reliably than they reproduce vocabulary. A word-swap list catches the surface; the named structural tells below catch the shape underneath, where most AI tone actually lives. Weight detection toward structure.
Vocabulary: delve, crucial, pivotal, foster, leverage, tapestry, testament, underscore, vibrant, landscape (abstract), shape (abstract, as in "previous shape" / "the shape of the problem"), interplay, multifaceted, enhance, enduring, garner, showcase, Additionally, seamless, robust, cutting-edge, groundbreaking, nestled, renowned
Structural tells:
- Rule of three: forced triads ("streamline, optimize, and enhance")
- Negative parallelism: "It's not just X -- it's Y" / "Not X. But Y." → state Y directly
- Superficial -ing phrases: "ensuring reliability", "showcasing features"
- Copula avoidance: "serves as", "stands as", "boasts" -- use "is", "has"
- Synonym cycling: four names for the same thing in four sentences
- False ranges: "from X to Y" where X and Y aren't on a meaningful scale
- Formulaic challenges: "Despite X, Y continues to thrive"
- Dramatic fragmentation: "[Noun]. That's it. That's the [thing]." -- performative simplicity
- Rhetorical setups: "What if I told you..." / "Think about it:" / "Here's what I mean:"
- Wh- sentence openers: sentences starting with What/When/Where/Which/Who/Why/How as filler. Restructure to lead with the subject or verb.
- Narrator-from-a-distance: "This happens because...", "People tend to...", "Nobody designed this." Put the reader in the room instead.
- Lazy extremes: every, always, never, everyone, nobody -- false authority. Use specifics instead of sweeping claims.
- Meta-commentary: "Hint:", "Plot twist:", "Spoiler:", "In this section, we'll...", "As we'll see...", "Let me walk you through..."
Formatting tells:
- Em dash overuse -- replace most with commas or periods
- Mechanical bold on every other phrase
- Emoji-decorated headers (exception: README section headers; see README Rules below)
- Bolded-header bullet lists (Thing: explanation of thing)
- Title Case In Every Heading Word -- use sentence case instead
Banned phrases -- delete and rewrite on sight. See references/phrases.md for the full list.
Core offenders:
- "In today's rapidly evolving landscape"
- "game-changer", "revolutionary", "transformative"
- "Moreover", "Furthermore", "Additionally" (as sentence starters)
- "It's worth noting that", "It is important to note that"
- "At the end of the day"
- "Here's the thing:" / "It turns out" / "Let me be clear" / "The uncomfortable truth is"
- "Full stop." / "Let that sink in." / "Make no mistake"
- "In order to" → "To" | "Due to the fact that" → "Because"
- Generic conclusions: "The future looks bright" → state the actual plan
Communication artifacts (remove entirely):
- "Great question!", "I hope this helps!", "Let me know if..."
- "As of my last update", "based on available information"
- Sycophantic openers and vague attributions ("Experts argue", "Industry reports suggest")
False Agency
AI avoids naming actors by giving inanimate things human verbs. Find the person; put them at the front of the sentence.
| AI slop | Fix |
|---|---|
| "the complaint becomes a fix" | Someone fixed it |
| "the data tells us" | Name who read it and what they concluded |
| "the decision emerges" | Someone decided |
| "the culture shifts" | People changed their behavior |
| "the market rewards" | Buyers paid for it |
| "the conversation moves toward" | Someone steered it |
| "a bet lives or dies" | Someone kills or ships it |
If no specific person fits, use "you" to put the reader in the seat. Person rules: use "you" when addressing the reader directly, "we" for organizational actions, "I" for personal voice. Avoid third-person passive ("it was decided") -- name the actor.
Quality Gate
Before delivering prose, run two checks:
Quick audit (binary, kill anything that triggers):
- Any adverbs? Kill them.
- Any passive voice? Find the actor, make them the subject.
- Inanimate thing doing a human verb? Name the person.
- "Not X, it's Y" contrast? State Y directly.
- Three consecutive sentences match length? Break one.
- Em-dash anywhere? Replace with comma or period.
- Vague declarative ("The implications are significant")? Name the specific implication.
- Meta-joiner ("The rest of this section...")? Delete. Let the text move.
Restraint -- over-editing is a failure mode, equal in weight to under-editing. A flagged item is a candidate, not a verdict.
- If a sentence already reads naturally, leave it. Touching prose that was fine introduces new tells and strips voice.
- Match the smell, not the string. A word on the vocabulary list that reads naturally in its actual context stays -- flag the tone, not the token. Banning a word everywhere it appears is mechanical editing, the same defect the skill exists to remove.
Five-dimension scoring (rate 1-10 each):
| Dimension | Question |
|---|---|
| Directness | Statements or announcements? |
| Rhythm | Varied or metronomic? |
| Trust | Respects reader intelligence? |
| Authenticity | Sounds human? |
| Density | Anything cuttable? |
Below 35/50: revise before delivering.
Long-form audit workflow -- for documents, essays, and research content, run a two-phase pass to avoid fix-as-you-go bias (fixing one tell while missing three others). This section reuses the vocabulary and structural tells from "AI Patterns -- Kill on Sight" above but adds named tags for tracking and a structured fix table. Short-form edits can use the Kill-on-Sight list directly; long-form audits should use the tag-based workflow below.
Phase 1 -- Audit: Read the full text without changing anything. Quote the shortest offending snippet (≤12 words) and append every applicable tag. Stack tags if multiple tells land in one sentence. One numbered line per offense. End with — END AUDIT: [n] issues found —. If zero, write — AUDIT COMPLETE: 0 issues — and skip Phase 2.
Tag vocabulary (extend the earlier prose rules with these named IDs):
| Tag | What it catches |
|---|---|
[FALSE-AGENCY] | Inanimate subject with a human verb ("the data tells us") |
[BINARY-CONTRAST] | "Not X, it's Y" / "It's not about X. It's about Y." constructions |
[STACCATO] | Punchy fragment sequences simulating manufactured rhythm ("This matters. A lot. Here's why.") |
[ELEGANT-VAR] | Synonym cycling: four names for the same entity across four sentences |
[NOT-ONLY-BUT] | False-pivot contrasts: "Not only X, but also Y" and variants |
[RULE-OF-3] | Forced triads ("streamline, optimize, and enhance") |
[INFLATED] / [PROMO] | Puffery and promotional gloss without a verifiable claim |
[SUPERFICIAL-ING] | Trailing -ing phrases that add no information ("ensuring reliability") |
[AI-LEX] | Vocabulary tells (delve, crucial, pivotal, leverage, tapestry, robust...) |
[VAGUE-ATTR] / [WEASEL] | "Experts argue", "studies show" without specific source |
[META-COMMENTARY] | Structural self-reference ("In this section, we'll...", "Let me walk you through...") |
[EM-DASH] | Any em or en dash -- restructure, don't preserve |
[INLINE-BOLD] / [INLINE-LIST] / [TITLE-CASE] | Mechanical formatting tells |
[VAGUE-DECLARATIVE] | "The implications are significant" without naming the implication |
[PASSIVE] / [ADVERB] / [BANNED-PHRASE] | Standard corrections |
[CURLY-QUOTES] | Curly single or double quotes (’ ‘ “ ”) in running prose. AI autocorrect artifact — replace with straight ASCII quotes. |
[EMOJI] | Emoji in running text or headings. Functional UI emoji in product copy is fine; editorial/promotional emoji is an AI tell. |
[FALSE-RANGE] | "From X to Y" where X and Y aren't on a coherent scale ("from code review to cultural shift"). Restructure to state both items without implying a continuum. |
Severity suffixes when tagging: +H for high severity (strong tell or compound patterns), +S for structural (affects document structure, not just wording).
Phase 2 -- Rewrite: Correct tagged items in a single pass using the fix table below. Preserve everything not flagged; no scope creep. Verify no new tells were introduced during rewriting.
| Tags | Fix action |
|---|---|
[INFLATED] [PROMO] [VAGUE-DECLARATIVE] | Delete puffery or replace with a specific factual claim. If no fact exists, cut entirely. |
[SUPERFICIAL-ING] | Remove the -ing phrase or convert to a separate sentence with substance. |
[AI-LEX] | Replace with a plainer synonym or restructure to eliminate the word. |
[NOT-ONLY-BUT] [RULE-OF-3] [BINARY-CONTRAST] | Break the pattern. State Y directly. |
[STACCATO] | Reconstruct into a single flowing sentence that matches the source material's natural rhythm. |
[ELEGANT-VAR] | Pick one term and use it consistently (or use pronouns). |
[VAGUE-ATTR] [WEASEL] | Name the source, add a quantifier, or delete the claim. |
[EM-DASH] | Remove entirely. Restructure the sentence: split, comma, colon, or rewrite. Never preserve the dash. |
[FALSE-AGENCY] | Name the human actor; put them at the front of the sentence. |
[META-COMMENTARY] | Delete. Let the text move without announcing itself. |
[INLINE-BOLD] [INLINE-LIST] [TITLE-CASE] | Strip excess formatting; sentence case for headings. |
For documents with references or citations, also tag: [OAICITE] (malformed AI citation artifacts), [LINK-ROT] (dead or placeholder URLs), [ISBN-DOI-FAIL] (invalid identifiers), [REF-BUG] (misformatted references, wrong numbering, dangling footnotes). See references/audit-workflow.md for the full procedure.
Output format:
## AUDIT
1. "quoted snippet" [TAG] [TAG +H]
2. "quoted snippet" [TAG]
...
— END AUDIT: [n] issues found —
## CORRECTED TEXT
[full corrected text]
## CHANGELOG
- Line/section: brief description of change
- Line/section: brief description of changeVoice
- Have opinions -- react to facts, don't just report them
- Vary rhythm -- short sentences, then longer ones. Mix it up.
- Acknowledge complexity -- "impressive but also unsettling" beats "impressive"
- Use first person when appropriate -- "I keep coming back to..." signals a real person
- Be specific about feelings -- not "this is concerning" but name what unsettles you
- Let some mess in -- fragments ("Because that's real."), conjunction starters ("But that changes everything."), parentheticals (thinking mid-sentence) -- all signal a human drafting, not generating
Composition
- One paragraph, one topic. Lead with the topic sentence.
- Keep related words together. Place emphatic words at end of sentence.
- Don't join independent clauses with a comma. Don't break sentences in two.
- Beginning participial phrase must refer to the grammatical subject.
- Match tone to context: casual for blogs, precise for docs, direct for UI text.
Self-Check
Short-form (commits, PR descriptions, comments): checks 1-4 only. Long-form (blog posts, docs, essays): run the full Quality Gate above, then checks 1-5.
1. Read every sentence aloud. If it sounds like a press release, Wikipedia, or chatbot -- rewrite. 2. Ctrl-F the banned-phrases list. Zero matches required. 3. Check for false agency: any inanimate thing performing a human verb? Name the person. 4. Check for em dash overuse, mechanical bold, and synonym cycling. 5. Cut quotables: if a sentence sounds like a pull-quote or aphorism, rewrite it.
Changelog Voice
- Sell test: every bullet should pass "would a user reading this think 'I want to try that'?" Lead with what the user can now do, not implementation details. "You can now filter by date range" not "Refactored the query builder to support date predicates"
- User-facing vs internal: internal changes (refactors, dependency bumps, CI fixes) belong in a separate "For contributors" subsection, not mixed with user-facing bullets
- Verb tense: past tense for what changed ("Added", "Fixed"), not present ("Adds", "Fixes")
PR / MR Descriptions
For pull-request and merge-request descriptions, match length to change complexity (1 sentence for trivial, full narrative for architecturally significant). Lead with Before / After / Scope rationale; describe net end state, not iteration journey; pick Mermaid for topology, tables for grids. See references/pr-descriptions.md for the sizing matrix, narrative frame, GitHub-specific hazards (#NN auto-link trap), and the self-check list.
README Rules
READMEs are a different surface than blog posts, social posts, or PR descriptions. The general anti-AI-tells rules apply, with these carve-outs:
- Em dash sweep is mandatory. Run
grep -c "—" README.mdbefore commit; result must be0. Em dashes are the highest-signal AI tell in technical marketing prose. Replace per role: - Bold lead-in for a definition:
Term — explanation→**Term**: explanation - Inline parenthetical:
name — qualifier→name (qualifier) - Hard break mid-sentence:
clause — clause→ split into two sentences or use; - Bullet attribution:
- foo — bar→- **foo**: bar - List/license style at the bottom:
Section — note→Section: note - Emoji headers are normal README idiom.
## 🚀 Features,## ⚡ Performance,## 📦 Installation,## 🛠️ Usageread as standard open-source convention, not as AI styling. The humanizer ban on emoji in social posts does NOT apply to README section headers. Use at most one per header, never inline in prose. - Plain-text star link, not a markdown URL.
If this saves you a debugging cycle, ⭐ star it!reads as a human ask.[⭐ Star on GitHub](https://...)reads as marketing chrome. - Hybrid merge on rewrites. When rewriting an existing README rather than authoring from scratch, classify each existing section into PRESERVE (technical accuracy, version pins, install commands, working code blocks), ADD (missing context the new draft introduces), REJECT (AI fluff, marketing voice, padding), FIX (wrong claims, stale versions, broken links). The default rewrite instinct is wholesale replacement; resist it. The existing README's technical content is usually correct; the voice is what's wrong.
- The self-check is per-section, not per-paragraph. A README has H2 sections that each serve one job (install, usage, configuration, troubleshooting). Each section is its own audit unit; one polished section next to a fluffy one is worse than uniform mediocrity.
See references/examples.md for before/after transformations.
Two-Phase Audit Workflow
Fix-as-you-go editing causes blind spots: correcting one tell shifts attention away from detecting others. Separate detection from correction to catch more issues.
Phase 1: Audit (detection only)
Read the full text start to finish. Tag every tell inline without fixing anything. Use these category tags:
Prose tells
| Tag | Trigger |
|---|---|
[FALSE-AGENCY] | Inanimate thing performing a human verb |
[BINARY-CONTRAST] | "Not X. But Y." / "Not because X. Because Y." / "The answer isn't X. It's Y." |
[META-COMMENTARY] | "The rest of this essay explains..." / "Let me walk you through..." / "In this section, we'll..." / "As we'll see..." / "I want to explore..." |
[JARGON] | Business buzzword with a simpler substitute (see phrases.md) |
[PASSIVE] | Passive voice hiding the actor |
[ADVERB] | -ly word, softener, intensifier, or hedge |
[BANNED-PHRASE] | Any phrase from the kill-on-sight list |
[SYNONYM-CYCLE] | Same concept renamed across consecutive sentences |
[VAGUE-DECLARATIVE] | Announces importance without naming the specific thing |
Citation tells (documentation and research contexts)
| Tag | Trigger |
|---|---|
[OAICITE] | Malformed AI citation artifacts -- [oai_citation:...], 【...†source】, or similar markup leaked from a language model's internal retrieval |
[LINK-ROT] | Dead URLs, placeholder links (example.com, #), or links that return 404 |
[ISBN-DOI-FAIL] | Invalid ISBN/DOI identifiers -- wrong check digit, truncated, or fabricated |
[REF-BUG] | Reference formatting errors: mismatched footnote numbers, dangling [1] with no matching entry, duplicate reference IDs, inconsistent citation style within the same document |
Audit output format
Produce a numbered list of findings before making any edits:
1. [FALSE-AGENCY] para 3: "the codebase resists change" -- name who finds it hard to change
2. [BINARY-CONTRAST] para 5: "Not speed. Clarity." -- state "Clarity matters" directly
3. [OAICITE] para 8: "[oai_citation:1]" -- remove artifact, add real citation or delete claim
4. [REF-BUG] footnotes: [3] referenced in text but missing from reference listPhase 2: Rewrite (correction only)
Work through the tagged findings in order. For each:
1. Apply the fix. 2. Re-read the surrounding paragraph to verify no new tells were introduced. 3. Mark the finding as resolved.
After completing all fixes, do one final read-through of the full text to catch any tells introduced during rewriting.
When to use each mode
- Short-form (commits, PR descriptions, comments, changelogs): single-pass Quick Audit from the main skill is sufficient.
- Long-form (blog posts, documentation, essays, reports): use the full two-phase workflow.
- Research content (papers, technical docs with citations): use both prose and citation tell categories.
Before/After Examples
Throat-clearing + binary contrast
Before:
"Here's the thing: building products is hard. Not because the technology is complex. Because people are complex. Let that sink in."
After:
"Building products is hard. Technology is manageable. People aren't."
Removed opener, binary contrast, emphasis crutch. Direct statements.
---
Filler + unnecessary reassurance
Before:
"It turns out that most teams struggle with alignment. The uncomfortable truth is that nobody wants to admit they're confused. And that's okay."
After:
"Teams struggle with alignment. Nobody admits confusion."
Cut hedging ("most"), removed throat-clearing phrases, deleted permission-granting ending.
---
Business jargon stack
Before:
"In today's fast-paced landscape, we need to lean into discomfort and navigate uncertainty with clarity. This matters because your competition isn't waiting."
After:
"Move faster. Your competition is."
Eliminated jargon entirely. Core message in six words.
---
Dramatic fragmentation
Before:
"Speed. Quality. Cost. You can only pick two. That's it. That's the tradeoff."
After:
"Speed, quality, cost -- pick two."
Single sentence. No performative emphasis.
---
Rhetorical setup
Before:
"What if I told you that the best teams don't optimize for productivity? Here's what I mean: they optimize for learning. Think about it."
After:
"The best teams optimize for learning, not productivity."
Direct claim. No rhetorical scaffolding.
---
False agency
Before:
"The complaint becomes a fix when the culture shifts toward accountability."
After:
"Someone fixed it. The team started owning problems instead of passing them."
Named the actors. Removed inanimate verbs.
---
Narrator-from-a-distance
Before:
"Nobody designs a toxic team culture. It happens gradually. People tend to optimize for comfort over truth."
After:
"You don't sit down one day and decide to stop telling your manager bad news. It just starts feeling easier not to."
Reader is in the room, not watching from above.
Extended Phrase Reference
Throat-Clearing Openers
Remove these announcement phrases. State the content directly.
- "Here's the thing:"
- "Here's what [X]" / "Here's this" / "Here's why"
- "The uncomfortable truth is"
- "It turns out"
- "The real [X] is"
- "Let me be clear"
- "The truth is,"
- "I'll say it again:"
- "I'm going to be honest"
- "Can we talk about"
- "Here's what I find interesting"
- "Here's the problem though"
Any "here's what/this/that" construction announces the point instead of making it. Cut it.
Emphasis Crutches
These add no meaning. Delete them.
- "Full stop." / "Period."
- "Let that sink in."
- "This matters because"
- "Make no mistake"
- "Here's why that matters"
Business Jargon
| Avoid | Use instead |
|---|---|
| Navigate (challenges) | Handle, address |
| Unpack (analysis) | Explain, examine |
| Lean into | Accept, embrace |
| Landscape (context) | Situation, field |
| Game-changer | Significant, important |
| Double down | Commit, increase |
| Deep dive | Analysis, examination |
| Take a step back | Reconsider |
| Moving forward | Next, from now |
| Circle back | Return to, revisit |
| On the same page | Aligned, agreed |
Adverbs
Kill all adverbs. No -ly words. No softeners, intensifiers, or hedges.
Specific offenders: really, just, literally, genuinely, honestly, simply, actually, deeply, truly, fundamentally, inherently, inevitably, interestingly, importantly, crucially
Filler phrases:
- "At its core"
- "In today's [X]"
- "It's worth noting"
- "At the end of the day"
- "When it comes to"
- "In a world where"
- "The reality is"
Meta-Commentary
Remove self-referential asides. The essay should move, not announce its own structure.
- "Hint:" / "Plot twist:" / "Spoiler:"
- "You already know this, but"
- "But that's another post"
- "The rest of this essay explains..."
- "Let me walk you through..."
- "In this section, we'll..."
- "As we'll see..."
- "I want to explore..."
Vague Declaratives
Sentences that announce importance without naming the specific thing. Replace with the specific thing.
- "The reasons are structural"
- "The implications are significant"
- "This is the deepest problem"
- "The stakes are high"
- "The consequences are real"
- "This is genuinely hard"
- "This is what leadership actually looks like"
Binary Contrast Structures
AI defaults to "not X, it's Y" framing. State Y directly without the contrast scaffolding.
- "Not because X. Because Y." -- just state Y
- "The answer isn't X. It's Y." -- state Y
- "It's not about X. It's about Y." -- state Y
- "stops being X and starts being Y" -- say what it becomes
- "less about X and more about Y" -- say what it's about
- "X gives way to Y" -- state the current state
- "from X to Y" (false ranges) -- name the specific thing
- "Beyond X, there's Y" -- state Y directly
- "X, yes. But Y." -- state both as facts
- "It's not just X -- it's Y" -- state Y
- "The real X isn't Y -- it's Z" -- state Z
Lazy Extremes
False authority through sweeping claims. Use specifics instead.
- "every", "always", "never", "everyone", "everybody", "nobody"
- "No one has ever..." / "Everyone knows..." / "This always happens"
These sound confident but say nothing. Name the specific cases, people, or frequency.
Negative Listing
Listing what something is not before revealing what it is. A rhetorical striptease.
- "Not a X... Not a Y... A Z." -- state Z directly
- "It wasn't X. It wasn't Y. It was Z." -- the reader doesn't need the runway
Fractal Summary
Restating the same point three times -- preview, state, recap -- as if the reader needs to be told what they're about to be told. Say it once.
- "what I'll tell you / what I'm telling you / what I told you" -- the essay structure that announces itself at every level; cut the preview and the recap
- "First, X. [section on X.] So that's X." -- the closing restatement adds nothing; delete it
- Opening a section by summarizing it, then closing by summarizing it again -- pick the body, drop the bookends
Trust the reader to hold one statement without scaffolding around it.
Analogy Test
Don't ban analogies; test them. Keep one only if it passes all three:
1. Load-bearing -- the point lands harder with the analogy than without. If the literal sentence is already clear, the analogy is decoration; cut it. 2. Holds one layer deeper -- the comparison survives a second step ("X is like Y" still works when you push on how Y behaves). If it breaks on contact, it misleads. 3. Gets through without explanation -- the reader understands it cold. If it needs "what I mean by this is...", the analogy failed; state the point directly.
Fail any one -- cut the analogy and say the thing literally.
Dramatic Fragmentation
Sentence fragments for manufactured profundity. Complete sentences. Trust content over presentation.
- "[Noun]. That's it. That's the [thing]." -- performative simplicity
- "X. And Y. And Z." -- staccato drama
- "This unlocks something. [Word]." -- artificial revelation
- "Not always. Not perfectly." -- hedging disguised as reassurance
Formulaic Constructions
- "By the time X, I was Y." -- narrative template, restructure
- "X that isn't Y" -- say "X is broken" directly
Narrator-from-a-Distance
Floating above the scene instead of putting the reader in it.
- "Nobody designed this." -- disembodied observation
- "This happens because..." -- lecturer voice
- "This is why..." -- same
- "People tend to..." -- armchair sociologist
Put the reader in the room. "You don't sit down and decide to..." beats "Nobody designed this."
Performative Emphasis
False intimacy or manufactured sincerity:
- "creeps in"
- "I promise" / "They exist, I promise"
Telling Instead of Showing
Announcing difficulty or significance rather than demonstrating it:
- "This is what X actually looks like"
- "actually matters"
- "This is genuinely hard"
If something is hard or significant, show the specific constraint. Don't announce it.
Rhythm
- Three-item lists: use two items or one. Triads are an AI tell.
- Questions answered immediately: let questions breathe or cut them.
Sentence Starters to Avoid
- Sentences starting with What/When/Where/Which/Who/Why/How -- restructure, lead with the subject or verb
- Paragraphs starting with "So" -- start with content
- Sentences starting with "Look," -- remove
PR and MR Description Style
Rules for writing pull-request and merge-request descriptions that senior engineers actually read, not skim.
Sizing matrix
Match the description length to the change complexity. Overwriting a trivial patch with a narrative wastes reviewer time; underwriting a structural change hides intent.
| Change shape | Description size |
|---|---|
| Typo, comment fix, single-line bug fix, dependency bump with no behavior change | 1 sentence |
| Small feature or fix touching 1-3 files, no architectural implications | 2-4 sentences |
| Non-trivial feature, new endpoint, new skill, multi-file refactor | Full narrative: Before / After / Scope rationale |
| Architecturally significant change, new module, migration, subsystem rewrite | Full narrative + rationale for decisions NOT taken |
Skip the template for trivial PRs. "Bump lodash to 4.17.21 for CVE-2021-23337." is complete on its own -- do not pad it.
Narrative frame (for non-trivial PRs)
Use three sections, in order:
Before -- what the code did / the system looked like before this change. One paragraph. Name the concrete state, not the abstract shape. "The renderMessage function serialized markdown synchronously in the request handler" beats "messaging was slow."
After -- what the code does / the system looks like now. Same paragraph shape. Describe the net end state, not the journey. The reviewer doesn't need to know you tried three approaches; they need to know what they're merging.
Scope rationale -- why this PR draws the line where it does. What's intentionally NOT included and why. This is the most-skipped section and the one reviewers value most -- it prevents "why didn't you also fix X?" review comments.
## Before
Authentication tokens were validated in each route handler via a helper call.
Token parsing logic was duplicated across 12 handlers, and the JWT secret
was read from env on every request.
## After
Authentication runs once in the `authRequired` middleware before any handler.
Token parsing is centralized; the secret is read once at process start.
## Scope rationale
- NOT changing the token format -- that's a separate migration in #1247
- NOT touching refresh-token flow -- the middleware is read-only for this PR
- NOT adding role-based authorization -- tracked in #1301Describe net end state, not iteration journey
The commit log is the journey. The description is the destination. If you wrote three approaches and kept the third, the description describes the third -- not all three.
Don't: "First I tried X but it didn't work because Y. Then I tried Z, which almost worked but ran into W. Finally I settled on V which handles both."
Do: "V replaces the previous X-based approach because V handles both the Y and W cases without the performance regression Z introduced."
Review drafts for "first I... then I... eventually..." phrasing -- rewrite toward the final state.
Visual choice: Mermaid vs table
When the change benefits from a visual, pick the shape based on what you're showing:
- Mermaid diagram -- topology with edges. Components that send messages to each other, request flow across services, a state machine's transitions, a dependency graph. Anything where the relationships are the point.
- Markdown table -- rows with parallel attributes. A before/after comparison of config values, a list of endpoints with their verbs and paths, a comparison of options with their tradeoffs. Anything where the structure is grid-shaped.
Mermaid for topology; table for grid. Neither for content that's genuinely prose -- don't force structure where it doesn't serve understanding.
GitHub-specific hazards
- Never prefix list items with `#<number>`: GitHub auto-links
#123at the start of any line as an issue/PR reference. Use a dash and backticks instead: - Wrong:
# 1. Fixed bug - Wrong:
#1 - Fixed bug - Right:
1. Fixed bugor- Fixed bug - Headings stay at H2 and below:
#(H1) is reserved for the PR title. Use##for section headings. - Code blocks use triple backticks, not quadruple -- GitHub renders quadruple-backtick blocks inconsistently across web vs API views.
Issue references: verify or omit
Include issue references (Fixes #1234, Closes JIRA-567, Related to #890) only when the exact ID or URL is present in user input, the branch name, a commit message, or verified tracker output. If you cannot point to where the ID came from, omit the line entirely -- the PR can ship without it.
Never emit placeholder IDs:
- Wrong:
Fixes #XXXXX/Closes <issue>/Related to #TBD/Fixes ABC-??? - Right: omit the line; the PR description is complete without an issue ref.
Hallucinated refs degrade the tracker (false links to the wrong issue, dead links to issues that don't exist) and noise up review threads. Verified refs are signal; placeholder refs are anti-signal.
Anti-patterns to strip
Apply the parent writing skill's banned-phrases list (no "delve", "leverage", "crucial", "game-changer", "in today's rapidly evolving landscape", etc.) in addition to these PR-specific offenders:
- "This PR..." opener -- redundant; the reader already knows it's a PR. Lead with the change.
- "Made some changes to..." -- say which changes. "Some" is an AI tell.
- "This should fix #1234" -- use "Fixes #1234" for auto-close, or "Related to #1234" if unsure. "Should" is hedging.
- Laundry-list commit message dumps in the description. The commit log is already there. Summarize the commits' net effect, don't reprint them.
- Emoji decoration on section headings. Sentence case, no emoji.
Test plan
Every non-trivial PR needs a Test Plan section. Bulleted markdown checklist so reviewers can see exactly what was exercised:
## Test plan
- [ ] `npm test` passes locally
- [ ] Manual: sign in with new SAML IdP, verify redirect to dashboard
- [ ] Manual: sign in with existing OAuth flow, verify no regression
- [ ] Staging: load test middleware at 500 rps for 5 min, p95 < 80msBe concrete. "Tested manually" is not a test plan. "Signed in with new SAML IdP, verified redirect" is.
Self-check before posting
Run these checks on the draft:
1. Can a reviewer who hasn't read the linked issue still understand what this PR does? If no, add context. 2. Is anything in the diff NOT mentioned in the description? Either describe it or question whether it belongs in this PR (scope drift). 3. Is the description longer than the diff deserves? Cut. 4. Did you use the word "simply" or "just"? Cut. 5. Did you claim the PR is "ready to merge"? Delete -- that's the reviewer's call.
ia-writing Specification
Intent
ia-writing is a discipline-class skill (an engineering practice not tied to one stack). Prose editing, rewriting, and humanizing text for natural tone. Use when asked to write, rewrite, edit, humanize, proofread, fix tone, or remove AI language. For copy, docs, blog posts, emails, or PRs.
Scope
In scope:
- Behaviors described in
SKILL.mdand routed via the should_trigger phrasings indistillery/tests/fixtures/triggers/ia-writing.jsonl. - Updates to runtime behavior, structure, trigger precision, references, and validation.
Out of scope:
- Acting as the runtime instructions themselves (those live in
SKILL.md). - Trigger phrasings already covered by adjacent
ia-*skills (validate-pluginflags >70% description overlap as DUPLICATE_TRIGGER). - <!-- to fill in: domain-specific exclusions when the skill drifts -->
Trigger Context
- Class:
discipline - Hook regex:
plugins/whetstone/hooks/skill-patterns.sh->SKILL_PATTERNS[ia-writing] - Common requests (from fixture should_trigger):
- "rewrite this paragraph to sound more natural"
- "write a PR description for the auth refactor"
- "audit this text for AI writing tells and fix them"
- Should not trigger for (from fixture should_not_trigger):
- "add an index on the created_at column"
- "debug the memory leak in the worker process"
- "check for citation issues and dead links in the documentation"
Source And Evidence Model
Authoritative sources:
SKILL.md-- runtime instructions and reference routing.references/*.md-- bundled supplementary content (4 file(s)).distillery/tests/fixtures/triggers/ia-writing.jsonl-- positive and negative trigger phrasings under regression test.plugins/whetstone/hooks/skill-patterns.sh-- regex pattern that fires this skill.distillery/.eval-data/ia-writing/-- harvested session examples (when present).
Data that must not be stored in this skill or its references:
- Secrets, credentials, tokens.
- Machine-specific filesystem paths (
/home/...,/Users/...,~/ai/...). The validator (MACHINE_PATH_LEAK) flags these as HIGH. - Private URLs, customer data, or unredacted personal information.
Coverage matrix
| Dimension | Status | Evidence |
|---|---|---|
| Trigger fixtures | complete | distillery/tests/fixtures/triggers/ia-writing.jsonl (>=5 should_trigger, >=5 should_not_trigger) |
| Hook regex pattern | complete | plugins/whetstone/hooks/skill-patterns.sh (SKILL_PATTERNS[ia-writing]) |
| Reference architecture | complete | 4 file(s) under references/ |
| Real-usage signal | <!-- populated by harvest-sessions when sessions exist --> | distillery/.eval-data/ia-writing/ (created by harvest-sessions) |
Evaluation
Lightweight (run on every change):
python3 distillery/scripts/distiller.py validate-plugin --component ia-writing
python3 distillery/scripts/distiller.py test-triggers --skill ia-writingDeeper (when behavior risk warrants):
python3 distillery/scripts/distiller.py dspy-eval ia-writing
python3 distillery/scripts/distiller.py diagnose-negatives ia-writingAcceptance gates:
validate-plugin --component ia-writingreturns 0 HIGH findings.test-triggers --skill ia-writingreturns F1 = 1.0 with floors of 5 should_trigger and 5 should_not_trigger.- For dspy-eval, the composite score does not regress against the most recent saved baseline (see
distillery/.eval-data/ia-writing/history.json).
Known Limitations
<!-- to fill in over time as drift surfaces. Default rule: any time diagnose-negatives surfaces a recurring failure pattern, document it here so future maintainers understand the trade-off the current implementation accepts. -->
Maintenance Notes
- Update
SKILL.mdwhen the runtime workflow, branch conditions, or output contract changes. - Update this
SPEC.mdwhen intent, scope, evidence model, evaluation gates, or maintenance expectations change. - Update the trigger fixture when adding new positive phrasings, removing stale ones, or expanding scope (the 5/5 floor is a hard validator gate).
- Update the hook regex in
skill-patterns.shwhenever fixture positives expose a missed phrasing; verify F1 = 1.0 witheval-triggersbefore committing. - Run the full release pipeline via
/release-- never bump versions or update CHANGELOG.md from a per-skill edit.