
Review Ai Writing
- 88 installs
- 74 repo stars
- Updated July 21, 2026
- existential-birds/beagle
Helps with ai & agent building tasks.
About
review-ai-writing is a Claude Code skill for ai & agent building. It helps solo builders move faster with AI-assisted development.
- review-ai-writing
- AI & Agent Building
- AI-coding skill
Review Ai Writing by the numbers
- 88 all-time installs (skills.sh)
- Ranked #4,935 of 16,546 AI & Agent Building skills by installs in the Skillselion catalog
- Data as of Jul 28, 2026 (Skillselion catalog sync)
npx skills add https://github.com/existential-birds/beagle --skill review-ai-writingAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 88 |
|---|---|
| repo stars | ★ 74 |
| Last updated | July 21, 2026 |
| Repository | existential-birds/beagle ↗ |
What it does
Helps with ai & agent building tasks.
Files
Review AI Writing
Detect AI-generated writing patterns across developer text artifacts, parallelizing across artifact groups when the agent supports it.
Usage
Invoke the review-ai-writing skill with optional flags: review-ai-writing [--all] [--category <name>] [path].
Flags:
--all- Scan entire codebase (default: changed files from main)--category <name>- Only check specific category:content|vocabulary|formatting|communication|filler|code_docs- Path: Target directory (default: current working directory)
Instructions
1. Parse Arguments
Extract flags from $ARGUMENTS:
--all- Full codebase scan--category <name>- Filter to specific category- Path - Target directory
2. Load Skills
Load the review-verification-protocol skill before reporting findings. The AI-writing pattern catalog lives in this file's Reference Material section and the references/*.md files — read the categories you intend to check.
3. Determine Scope
# Default: changed files from main
git diff --name-only $(git merge-base HEAD main)..HEAD
# If --all flag: scan all text artifacts
find . -type f \( -name "*.md" -o -name "*.py" -o -name "*.ts" -o -name "*.tsx" -o -name "*.js" -o -name "*.jsx" -o -name "*.go" -o -name "*.rs" -o -name "*.java" -o -name "*.rb" -o -name "*.swift" -o -name "*.kt" -o -name "*.ex" -o -name "*.exs" \) ! -path "*/node_modules/*" ! -path "*/.git/*" ! -path "*/vendor/*" ! -path "*/__pycache__/*" ! -path "*/dist/*" ! -path "*/build/*"If no files found, exit with: "No files to scan. Check your branch has changes or use --all."
4. Check for Existing LLM Artifacts Review
# Check if llm-artifacts review exists to avoid double-flagging
if [ -f .beagle/llm-artifacts-review.json ]; then
echo "Found existing llm-artifacts review — will skip overlapping findings"
fiParse existing findings from .beagle/llm-artifacts-review.json if present. When consolidating, skip any finding where both the file:line and pattern type match an existing llm-artifacts finding (specifically verbose_comment and over_documentation types).
5. Classify Files by Type
Partition files into three groups:
| Group | File Types | Patterns to Check |
|---|---|---|
| Prose | *.md | All 6 categories |
| Code Docs | *.py, *.ts, *.tsx, *.js, *.jsx, *.go, *.rs, *.java, *.rb, *.swift, *.kt, *.ex, *.exs | vocabulary, communication, filler, code_docs |
| Git | Commit messages, PR descriptions | content, vocabulary, communication, filler |
For Git artifacts, collect recent commits:
# Commits on current branch not in main
git log --format="%H %s" $(git merge-base HEAD main)..HEAD6. Scan Each Artifact Group
There are three artifact groups below (Prose, Code Docs, Git). If the agent supports subagents and total items >= 4, dispatch one subagent per in-scope group in parallel (up to 3); otherwise run the same group instructions sequentially yourself — identical output either way. If --category is set, handle only the matching category. Every subagent (or sequential pass) reads this skill's Reference Material and the relevant references/*.md patterns before scanning.
Group 1: Prose
Scope: Markdown files only Check: All 6 pattern categories Instructions: 1. Read each markdown file 2. Scan for all pattern categories 3. Apply the false positive checks from this skill 4. Return findings in the structured format
Group 2: Code Docs
Scope: Source code files Check: vocabulary, communication, filler, code_docs categories Instructions: 1. Extract docstrings and comments from each file 2. Scan for applicable pattern categories 3. Skip code itself — only check text in comments and docstrings 4. Return findings in the structured format
Group 3: Git
Scope: Commit messages and PR descriptions Check: content, vocabulary, communication, filler categories Instructions: 1. Read commit messages from the branch 2. If on a PR branch, read the PR description via gh pr view --json body 3. Scan for applicable pattern categories 4. Use synthetic paths: git:commit:<sha> with line 0, git:pr:<number> with line 0 5. Return findings in the structured format
7. Consolidate Findings
Wait for all subagents to complete, then:
1. Merge all findings into a single list 2. Remove duplicates (same file:line and type) 3. Remove findings that overlap with .beagle/llm-artifacts-review.json 4. Assign unique IDs (1, 2, 3...) 5. Group by category for display
8. Write JSON Report
Create .beagle directory if it doesn't exist:
mkdir -p .beagleWrite findings to .beagle/ai-writing-review.json:
{
"version": "1.0.0",
"created_at": "2025-01-15T10:30:00Z",
"git_head": "abc1234",
"scope": "changed",
"files_scanned": 12,
"commits_scanned": 5,
"findings": [
{
"id": 1,
"category": "vocabulary",
"type": "ai_vocabulary_high",
"file": "README.md",
"line": 15,
"original_text": "This library leverages cutting-edge algorithms to facilitate seamless data processing.",
"description": "High-signal AI vocabulary: leverage, cutting-edge, facilitate, seamless",
"suggestion": "This library uses streaming algorithms for fast data processing.",
"risk": "Low",
"fix_safety": "Safe",
"fix_action": "rewrite"
},
{
"id": 2,
"category": "code_docs",
"type": "tautological_docstring",
"file": "src/auth.py",
"line": 42,
"original_text": "\"\"\"Get the user by ID.\"\"\"",
"description": "Docstring restates function name get_user_by_id without adding value",
"suggestion": "\"\"\"Raises UserNotFound if ID doesn't exist.\"\"\"",
"risk": "Medium",
"fix_safety": "Needs review",
"fix_action": "rewrite"
},
{
"id": 3,
"category": "communication",
"type": "chat_leak",
"file": "git:commit:abc1234",
"line": 0,
"original_text": "Certainly! Here's the updated authentication flow",
"description": "Chat leak in commit message: starts with 'Certainly! Here's'",
"suggestion": "Update authentication flow",
"risk": "Low",
"fix_safety": "Safe",
"fix_action": "rewrite"
}
],
"summary": {
"total": 3,
"by_category": {
"vocabulary": 1,
"code_docs": 1,
"communication": 1
},
"by_risk": {
"Low": 2,
"Medium": 1
},
"by_fix_safety": {
"Safe": 2,
"Needs review": 1
}
}
}9. Display Summary
## AI Writing Review
**Scope:** Changed files from main
**Files scanned:** 12 | **Commits scanned:** 5
### Findings by Category
#### Vocabulary (1 issue)
1. [README.md:15] **AI vocabulary** (Low, Safe)
- High-signal AI vocabulary: leverage, cutting-edge, facilitate, seamless
- Suggestion: Rewrite with simple words
#### Code Docs (1 issue)
2. [src/auth.py:42] **Tautological docstring** (Medium, Needs review)
- Docstring restates function name without adding value
- Suggestion: Add meaningful information or delete
#### Communication (1 issue)
3. [git:commit:abc1234:0] **Chat leak** (Low, Safe)
- Commit message starts with "Certainly! Here's"
- Suggestion: Rewrite as imperative commit message
### Summary Table
| Category | Safe | Needs Review | Total |
|----------|------|--------------|-------|
| Vocabulary | 1 | 0 | 1 |
| Code Docs | 0 | 1 | 1 |
| Communication | 1 | 0 | 1 |
| **Total** | **2** | **1** | **3** |
### Next Steps
- Invoke the humanize-beagle skill to apply fixes
- Invoke the humanize-beagle skill with --dry-run to preview changes first
- Review the JSON report at `.beagle/ai-writing-review.json`10. Verification
Before completing, all of the following must pass (objective checks):
1. JSON file exists and parses: .beagle/ai-writing-review.json is present or you exited at Gate 1 with no scan (then no JSON is required). 2. JSON validity: If the file exists, python3 -c "import json; json.load(open('.beagle/ai-writing-review.json'))" exits 0. 3. Subagent success: If you dispatched subagents, each returned without tool/runtime failure (a failed dispatch = do not write final JSON as if complete). 4. Git HEAD captured: When JSON exists, git_head matches git rev-parse HEAD (non-empty string). 5. No double-flagging: If .beagle/llm-artifacts-review.json exists, no finding duplicates its file:line + overlapping type for the skip rules in §4.
# Verify JSON is valid (when file exists)
python3 -c "import json; json.load(open('.beagle/ai-writing-review.json'))" 2>/dev/null && echo "Valid JSON" || echo "Invalid JSON"If any check fails, report the error and do not proceed.
Output Format for Each Finding
[FILE:LINE] ISSUE_TITLE
- Category: content | vocabulary | formatting | communication | filler | code_docs
- Type: specific_pattern_name
- Original: "the problematic text"
- Suggestion: "the improved text" or "delete"
- Risk: Low | Medium
- Fix Safety: Safe | Needs reviewRules
- Always read this skill's pattern catalog and load review-verification-protocol first
- If the agent supports subagents, parallelize across artifact groups when >= 4 items to scan; otherwise scan sequentially
- Every finding MUST have file:line reference (use synthetic paths for git artifacts)
- Do not flag false positives listed in the skill
- Do not duplicate findings from
.beagle/llm-artifacts-review.json - Create
.beagledirectory if needed - Write JSON report before displaying summary
Gates (sequenced pass conditions)
Advance only when each pass condition is satisfied using artifacts (paths, exit codes, parseable output)—not an internal “I checked” claim.
1. Arguments → scope
- Pass: You can list the concrete paths (or
git:commit:<sha>/git:pr:<n>) you will scan. If that set is empty, emit the “No files to scan…” message and do not create.beagle/ai-writing-review.json.
2. Scope → execution
- Pass: Each of Prose, Code docs, and Git (when in scope) has either completed subagent output or equivalent inline work with the same structured fields per finding.
3. Consolidation → write
- Pass: Duplicates (same file:line and type) removed; when
.beagle/llm-artifacts-review.jsonexists, overlaps with it skipped per §4;git_headequals the output ofgit rev-parse HEAD(non-empty).
4. JSON → summary
- Pass:
python3 -c "import json; json.load(open('.beagle/ai-writing-review.json'))"exits 0.
5. Finding → verification protocol
- Pass: For each reported issue, you can cite the surrounding paragraph or function you used so the flag is evidence-backed (see review-verification-protocol).
Reference Material
AI Writing Detection for Developer Text
Detect patterns characteristic of AI-generated text in developer artifacts. These patterns reduce trust, add noise, and obscure meaning.
Pattern Categories
| Category | Reference | Key Signals |
|---|---|---|
| Content | references/content-patterns.md | Promotional language, vague authority, formulaic structure, synthetic openers |
| Vocabulary | references/vocabulary-patterns.md | AI word tiers, copula avoidance, rhetorical devices, synonym cycling, commit inflation |
| Formatting | references/formatting-patterns.md | Boldface overuse, emoji decoration, heading restatement |
| Communication | references/communication-patterns.md | Chat leaks, cutoff disclaimers, sycophantic tone, apologetic errors |
| Filler | references/filler-patterns.md | Filler phrases, excessive hedging, generic conclusions |
| Code Docs | references/code-docs-patterns.md | Tautological docstrings, narrating obvious code, "This noun verbs", exhaustive enumeration |
Scope
Scan these artifact types:
| Artifact | File Patterns | Notes |
|---|---|---|
| Markdown docs | *.md | READMEs, guides, changelogs |
| Docstrings | *.py, *.ts, *.js, *.go, *.swift, *.rs, *.java, *.kt, *.rb, *.ex | Language-specific docstring formats |
| Code comments | Same as docstrings | Inline and block comments |
| Commit messages | git log output | Use synthetic path git:commit:<sha> |
| PR descriptions | GitHub PR body | Use synthetic path git:pr:<number> |
What NOT to Scan
- Generated code (lock files, compiled output, vendor directories)
- Third-party content (copied license text, vendored docs)
- Code itself (variable names, string literals used programmatically)
- Test fixtures and mock data
Detection Rules
High-Confidence Signals (Always Flag)
These patterns are strong indicators of AI-generated text:
1. Chat leaks — "Certainly!", "I'd be happy to", "Great question!", "Here's" as sentence opener 2. Cutoff disclaimers — "As of my last update", "I cannot guarantee" 3. High-signal AI vocabulary — delve, utilize (as "use"), whilst, harnessing, paradigm, synergy 4. "This noun verbs" in docstrings — "This function calculates", "This method returns" 5. Synthetic openers — "In today's fast-paced", "In the world of" 6. Sycophantic code comments — "Excellent approach!", "Great implementation!"
Medium-Confidence Signals (Flag in Context)
Flag when 2+ appear together or pattern is repeated:
1. Low-signal AI vocabulary clusters — 3+ words from the low-signal list in one section 2. Formulaic structure — Rigid intro-body-conclusion in a README section 3. Heading restatement — First sentence after heading restates the heading 4. Excessive hedging — "might potentially", "could possibly", "it seems like it may" 5. Synonym cycling — Same concept called different names within one section 6. Boldface overuse — More than 30% of sentences contain bold text
Low-Confidence Signals (Note Only)
Mention but don't flag as issues:
1. Emoji in technical docs — May be intentional project style 2. Filler phrases — Some are common in human writing too 3. Generic conclusions — May be appropriate for summary sections 4. Commit inflation — Some teams prefer descriptive commits
False Positive Warnings
Do NOT flag these as AI-generated:
| Pattern | Why It's Valid |
|---|---|
| "Ensure" in security docs | Standard term for security requirements |
| "Comprehensive" in test coverage discussion | Accurate technical descriptor |
| Formal tone in API reference docs | Expected register for reference material |
| "Leverage" in financial/business domain code | Domain-specific meaning, not AI filler |
| Bold formatting in CLI help text | Standard convention |
| Structured intro paragraphs in RFCs/ADRs | Expected format for these document types |
"This module provides" in Python __init__.py | Idiomatic Python module docstring |
| Rhetorical questions in blog posts | Appropriate for informal content |
Integration
With review-verification-protocol
Before reporting any finding:
1. Read the surrounding context (full paragraph or function) 2. Confirm the pattern is AI-characteristic, not just formal writing 3. Check if the project has established conventions that match the pattern 4. Verify the suggestion improves clarity without changing meaning
With llm-artifacts-detection
Code-level patterns (tautological docstrings, obvious comments) overlap with llm-artifacts-detection's style criteria. When both skills are loaded:
review-ai-writingfocuses on writing style (how it reads)llm-artifacts-detectionfocuses on code artifacts (whether it should exist at all)- If
.beagle/llm-artifacts-review.jsonexists, skip findings already captured there
Output Format
Report each finding as:
[FILE:LINE] ISSUE_TITLE
- Category: content | vocabulary | formatting | communication | filler | code_docs
- Type: specific_pattern_name
- Original: "the problematic text"
- Suggestion: "the improved text" or "delete"
- Risk: Low | Medium
- Fix Safety: Safe | Needs reviewRisk Levels
- Low — Filler phrases, obvious comments, emoji. Removing improves clarity with no meaning change.
- Medium — Vocabulary swaps, structural changes, docstring rewrites. Meaning could shift if done carelessly.
Fix Safety
- Safe — Mechanical replacement or deletion. No judgment needed.
- Needs review — Rewrite requires understanding context. Human should verify the replacement preserves intent.
Code Documentation Patterns
Detecting AI-generated writing in developer documentation: docstrings, code comments, commit messages, and PR descriptions.
Overlap note: Tautological docstrings and obvious comments also appear in llm-artifacts-detection (style-criteria.md). This file focuses on the AI writing style aspect; the artifacts skill focuses on unnecessary code artifacts.
---
1. Tautological Docstrings
What to Look For
Docstrings that restate the function name, parameters, or signature without adding any information a developer couldn't already read from the code. The docstring is a mirror of the declaration, not a supplement to it.
Common tells:
- Docstring is the function name split into words
- Describes the return value using only the return type
- Begins with a verb form of the function name ("Gets", "Sets", "Returns", "Creates")
Examples
Python
# BAD - restates the function name
def get_user(user_id: int) -> User:
"""Gets the user."""
return db.query(User).filter_by(id=user_id).one()
def __init__(self, config: Config):
"""Initializes the class."""
self.config = config
def get_count(self) -> int:
"""Returns the count."""
return self._count
# GOOD - adds information not in the signature
def get_user(user_id: int) -> User:
"""Raises NoResultFound if the user does not exist."""
return db.query(User).filter_by(id=user_id).one()
def __init__(self, config: Config):
"""Starts background sync if config.auto_sync is enabled."""
self.config = config
if config.auto_sync:
self._start_sync()
# GOOD - trivial function, no docstring needed
def get_count(self) -> int:
return self._countTypeScript
// BAD - restates the function name
/** Gets the user by ID. */
function getUserById(id: string): User {
return users.get(id);
}
/** Creates a new order. */
function createOrder(items: CartItem[]): Order {
return orderService.create(items);
}
// GOOD - explains non-obvious behavior
/** Falls back to guest user if ID is not found. */
function getUserById(id: string): User {
return users.get(id) ?? GUEST_USER;
}
// GOOD - no doc needed for clear functions
function createOrder(items: CartItem[]): Order {
return orderService.create(items);
}fix_safety: Safe. Removing a tautological docstring or replacing it with useful content does not change behavior.
---
2. Narrating Obvious Code
What to Look For
Comments that describe what the code does line-by-line rather than explaining why. These read like a narration of the syntax rather than a note from one developer to another. They add vertical noise without aiding comprehension.
Common tells:
- Comment restates the operation:
# Loop through items,# Check if valid - Comment names the construct:
# Return the result,# Set the variable - Every block has a comment even when the code is self-documenting
Examples
Python
# BAD - narrates each line
def process_orders(orders: list[Order]) -> list[Receipt]:
# Initialize results list
results = []
# Loop through orders
for order in orders:
# Check if order is valid
if order.is_valid():
# Process the order
receipt = order.process()
# Add receipt to results
results.append(receipt)
# Return the results
return results
# GOOD - comment only where non-obvious
def process_orders(orders: list[Order]) -> list[Receipt]:
results = []
for order in orders:
if order.is_valid():
# process() is idempotent; safe to retry on partial failures
receipt = order.process()
results.append(receipt)
return resultsJavaScript
// BAD - narrates obvious DOM operations
function renderList(items) {
// Get the container element
const container = document.getElementById("list");
// Clear existing content
container.innerHTML = "";
// Iterate over items
items.forEach((item) => {
// Create a new list item
const li = document.createElement("li");
// Set the text content
li.textContent = item.name;
// Append to container
container.appendChild(li);
});
}
// GOOD - no comments needed; code is clear
function renderList(items) {
const container = document.getElementById("list");
container.innerHTML = "";
items.forEach((item) => {
const li = document.createElement("li");
li.textContent = item.name;
container.appendChild(li);
});
}fix_safety: Safe. Removing narration comments does not change behavior. Keep any comment that explains a non-obvious decision or constraint.
---
3. "This noun verbs" Pattern
What to Look For
Docstrings and descriptions that start with "This function...", "This method...", "This class...", "This module...". This is a signature AI sentence structure rarely used by human developers. Humans typically write in imperative mood ("Calculate totals") or start with the subject of the action ("Totals are calculated..."), not with a self-referential "This".
Common tells:
- "This function calculates..."
- "This method returns..."
- "This class represents..."
- "This module provides..."
- "This component renders..."
- "This hook manages..."
Examples
Python
# BAD - "This function/class/method" pattern
class OrderProcessor:
"""This class represents an order processor that handles
the processing of customer orders."""
def calculate_total(self, items: list[Item]) -> Decimal:
"""This method calculates the total price for the given items."""
return sum(item.price * item.quantity for item in items)
def apply_discount(self, total: Decimal, code: str) -> Decimal:
"""This function applies a discount code to the total."""
discount = self.discounts.get(code, Decimal("0"))
return total - discount
# GOOD - imperative mood, no self-reference
class OrderProcessor:
"""Process customer orders with discount and tax support."""
def calculate_total(self, items: list[Item]) -> Decimal:
"""Sum of price * quantity across all items."""
return sum(item.price * item.quantity for item in items)
def apply_discount(self, total: Decimal, code: str) -> Decimal:
"""Subtract the discount for `code`. Unknown codes are ignored."""
discount = self.discounts.get(code, Decimal("0"))
return total - discountTypeScript
// BAD - "This component/hook" pattern
/**
* This component renders a user profile card with the user's
* avatar, name, and bio information.
*/
function ProfileCard({ user }: { user: User }) {
return <Card>...</Card>;
}
/**
* This hook manages the authentication state for the application.
*/
function useAuth(): AuthState {
// ...
}
// GOOD - direct description
/** User profile card showing avatar, name, and bio. */
function ProfileCard({ user }: { user: User }) {
return <Card>...</Card>;
}
/** Authentication state with login, logout, and token refresh. */
function useAuth(): AuthState {
// ...
}fix_safety: Safe. Rewriting a docstring from "This function does X" to imperative or direct style does not change behavior.
---
4. Exhaustive Enumeration
What to Look For
Documentation that exhaustively lists every parameter, return value, and exception even when most are obvious from the type signature. AI models tend to produce complete Args/Returns/Raises blocks as boilerplate regardless of whether the information is useful. The result is a docstring longer than the function body that a developer will skip entirely.
Common tells:
- Args section where every description is "The [param name]" or "The [param name] to use"
- Returns section that restates the return type hint
- Raises section listing only the obvious (
ValueErrorfor bad input) - Docstring is longer than the function body
Examples
Python
# BAD - exhaustive enumeration of obvious params
def send_notification(
user_id: int,
message: str,
channel: Channel = Channel.EMAIL,
) -> bool:
"""Send a notification to a user.
Args:
user_id: The ID of the user to notify.
message: The notification message to send.
channel: The channel to send the notification through.
Defaults to Channel.EMAIL.
Returns:
bool: True if the notification was sent successfully,
False otherwise.
Raises:
ValueError: If user_id is invalid.
ConnectionError: If the notification service is unavailable.
"""
...
# GOOD - document only non-obvious aspects
def send_notification(
user_id: int,
message: str,
channel: Channel = Channel.EMAIL,
) -> bool:
"""Send a notification. Returns False if delivery is deferred
(e.g., user has DND enabled) rather than raising."""
...TypeScript
// BAD - JSDoc repeats what the types already say
/**
* Fetches paginated results from the API.
*
* @param endpoint - The API endpoint to fetch from.
* @param page - The page number to fetch.
* @param pageSize - The number of items per page.
* @returns A promise that resolves to an array of results.
* @throws {ApiError} If the request fails.
*/
async function fetchPage<T>(
endpoint: string,
page: number,
pageSize: number
): Promise<T[]> {
// ...
}
// GOOD - only document what types don't convey
/**
* Fetch a page of results. Uses cursor-based pagination under
* the hood; `page` is translated to a cursor internally.
*/
async function fetchPage<T>(
endpoint: string,
page: number,
pageSize: number
): Promise<T[]> {
// ...
}fix_safety: Needs review. Removing parameter documentation is safe for obvious params, but verify that no non-obvious constraints or side effects are documented in the verbose block before trimming. Keep docs for params with subtle semantics (units, boundaries, format expectations).
---
Review Questions
When evaluating code documentation for these patterns, ask:
1. Does this docstring tell me something the signature does not? 2. Does this comment explain why, or just restate what? 3. Would a human developer actually write "This function..." in a docstring? 4. Is this Args/Returns/Raises block earning its vertical space? 5. If I deleted this documentation, would any developer be worse off?
Communication Patterns
Detection criteria for conversational AI artifacts that leak into developer-facing text: documentation, commit messages, PR descriptions, and code comments.
1. Chat Leaks
What to Look For
Conversational phrases from AI chat sessions copy-pasted into committed text. These read as one side of a dialogue rather than authored documentation.
Detection Patterns
# BAD - Chat openers leaked into docs/PRs/comments
Certainly! Here's how to configure the database connection.
Great question! The middleware stack processes requests in order.
I'd be happy to help explain the authentication flow.
# GOOD
Configure the database connection with the following environment variables.
The middleware stack processes requests in order.# BAD - Chat phrasing in code comments or commit messages
# Here's the implementation for the retry logic
# Let me explain what this does
# As requested, this handles the edge case
# Sure thing! This validates the token format
# GOOD
# Retry with exponential backoff, max 3 attempts
# Handles empty input by returning earlyfix_safety: Safe
Removing chat preambles does not change technical meaning.
---
2. Cutoff Disclaimers
What to Look For
Training cutoff disclaimers or knowledge-limitation hedges in docs or comments. These expose AI-generated origin and erode reader confidence.
Detection Patterns
# BAD
As of my last update, the API supports cursor-based pagination.
Based on current knowledge, PostgreSQL 16 introduced merge joins.
I cannot guarantee this behavior will remain consistent.
# GOOD
The API supports cursor-based pagination (v2.3+).
PostgreSQL 16 introduced merge joins (see release notes).
This behavior may change; pin your dependency version.fix_safety: Safe
Replace disclaimers with versioned references or remove entirely.
---
3. Sycophantic Tone
What to Look For
Excessive praise or enthusiasm in code review comments, PR descriptions, and documentation that reads as flattery rather than technical assessment.
Detection Patterns
# BAD
Excellent approach! The factory pattern here is wonderful.
Great implementation! This is a really elegant solution.
This is a brilliant way to handle the race condition!
# GOOD
The factory pattern decouples instantiation from the handler logic.
The mutex prevents the race condition identified in #247.
Consider a read-write lock since reads outnumber writes 10:1.# BAD
# This is a really nice pattern for dependency injection
# GOOD
# Dependency injection via constructor allows test doublesfix_safety: Safe
Replace praise with neutral technical descriptions. No semantic meaning is lost.
---
4. Apologetic Errors
What to Look For
Over-apologizing in error messages, log output, or documentation. Error handling should be informative and actionable, not socially polite.
Detection Patterns
# BAD
raise ValueError("I apologize for any inconvenience, but the input is invalid.")
logger.error("Sorry for the confusion, but the config could not be loaded.")
print("Unfortunately, we regret to inform you that the connection failed.")
# GOOD
raise ValueError(f"Invalid input: expected ISO 8601 date, got {value!r}")
logger.error("Failed to load config from %s: %s", config_path, err)
print(f"Connection failed: {host}:{port} (timeout after {timeout}s)")# BAD
We're sorry, but this feature is not available in the free tier.
# GOOD
This feature requires a paid plan. See pricing for details.fix_safety: Needs review
Error message rewording must preserve all diagnostic information (codes, paths, values). Verify the replacement includes the same actionable details.
---
Review Questions
1. Does the text read like one side of a conversation or like authored documentation? 2. Are there hedges or disclaimers that reference AI knowledge limitations? 3. Does review feedback contain praise without specific technical substance? 4. Do error messages apologize instead of providing actionable remediation steps? 5. Would the text make sense if the reader had no context of an AI interaction?
Content Patterns
Detection patterns for AI-generated writing in developer docs, commit messages, PRs, and code comments.
1. Promotional Language
What to Look For
Inflated claims about code quality or tool capabilities. AI text oversells what code does, using marketing language instead of precise technical description.
Detection Patterns
Commit messages:
Before:
feat: add robust and elegant caching layer for seamless data retrievalAfter:
feat: add Redis cache for user profile queriesModule docs:
Before:
This powerful and highly flexible authentication module provides a comprehensive,
enterprise-grade solution for all your security needs.After:
Authentication module supporting OAuth 2.0 and SAML. Wraps `authlib` with
project-specific defaults and middleware hooks.Inline comments:
Before: // This elegant algorithm efficiently handles all edge cases
After: // Handles duplicate keys by keeping the last value
Trigger Words
robust, elegant, seamless, powerful, comprehensive, cutting-edge, best-in-class, enterprise-grade, highly flexible, state-of-the-art, effortlessly
fix_safety: Safe
Replace promotional adjectives with factual descriptions of what the code actually does.
---
2. Vague Authority
What to Look For
Unattributed claims borrowing authority from unnamed sources. AI text inserts "research shows" or "experts agree" without citations.
Detection Patterns
Docs:
Before:
Research shows that structured error handling significantly improves reliability.
Experts agree that the Result pattern is the preferred approach.After:
Uses the Result pattern (`Ok`/`Err`) instead of exceptions.
See ADR-0012 (the Result-pattern decision record) for the tradeoff discussion.PR descriptions:
Before:
Studies have shown that smaller functions lead to better maintainability.
This refactor follows industry-standard practices.After:
Split `process_order` (180 lines) into `validate_order`, `apply_discounts`,
and `submit_order`. Each function is independently testable.Code comments:
Before: // Best practices dictate that we should validate input here
After: // Validate before insert; see #422 for the injection that motivated this
Trigger Phrases
research shows, studies have shown, experts agree, it is widely recognized, best practices dictate, industry-standard, as recommended by leading engineers
fix_safety: Safe
Replace with specific references (links, ADR numbers, issue numbers) or drop the claim entirely.
---
3. Formulaic Structure
What to Look For
Rigid intro-body-conclusion scaffolding where it adds no value. AI text forces three-act structure onto commit messages and short docs.
Detection Patterns
Over-structured commit messages:
Before:
feat: implement user notification system
Introduction:
This commit introduces a notification system for users.
Changes Made:
- Added NotificationService class
- Added email template
Conclusion:
Users will now receive email notifications when orders are processed.After:
feat: add email notifications on order completion
- Add NotificationService with SendGrid transport
- Add order_completed email template
- Add notifications table migrationUnnecessary preamble in docs:
Before:
## Configuration
Configuration plays a vital role in any application. In this section,
we will explore the various configuration options available.
### Database URLAfter:
## Configuration
### Database URLRestated conclusions:
Before:
## Conclusion
In summary, this library provides CSV parsing for your data pipeline.
As discussed above, it supports custom delimiters. We hope you find it useful.After: Remove the section, or replace with a "See also" list linking to related docs.
fix_safety: Safe
Removing empty intros, restated conclusions, and "in this section we will" preambles does not alter technical content.
---
4. Synthetic Openers
What to Look For
Canned opening phrases that add no information and delay the reader. Common in generated docs, PR descriptions, and READMEs.
Detection Patterns
Docs:
Before:
In today's fast-paced world of API development, rate limiting has become
an essential component of any production-ready system.After:
Token bucket rate limiter for the public API. Defaults to 100 req/min
per API key. Configure via `RATE_LIMIT` in environment.PR descriptions:
Before:
In the world of distributed systems, message queues play a crucial role
in decoupling services. This PR adds RabbitMQ support to our pipeline.After:
Add RabbitMQ consumer for the ingestion pipeline. Replaces the polling
loop in `ingest_worker.py` (see #287 for latency benchmarks).Code comments:
Before: // As we all know, caching is important for performance
After: // Cache parsed configs; parsing takes ~200ms per file
Trigger Phrases
In today's fast-paced, In the world of, In the ever-evolving landscape, As we all know, It's worth noting that, It goes without saying, When it comes to, In the realm of
fix_safety: Needs review
Most synthetic openers can be deleted outright, but some may be the only sentence introducing a topic. After removing the opener, verify the paragraph still has a clear lead sentence. If the opener was the entire introduction, write a direct replacement stating scope or purpose.
---
Review Questions
1. Does this description say what the code does, or how great it is? 2. Is this claim attributed to a specific source, or does it lean on vague authority? 3. Would this doc lose any technical content if the intro and conclusion were deleted? 4. Does the opening sentence deliver information, or is it a generic warm-up? 5. Could a reader skip the first paragraph entirely and miss nothing?
Filler Patterns
Patterns for detecting AI-generated filler in developer documentation, commit messages, PRs, and code comments.
Filler Phrases
Dev-specific filler phrases that add no information. These weaken technical writing by burying the actual point.
Cross-reference: See docs-style for the core phrase simplification table.
The following are dev-specific additions commonly found in AI-generated output:
| Phrase | Fix |
|---|---|
| "It's worth noting that" | Delete, or state the fact directly |
| "It should be noted that" | Delete |
| "As mentioned earlier/above" | Link directly to the section, or delete |
| "This allows us to" | State what happens |
| "In this section, we will" | Delete; just start the section |
| "Let's take a look at" | Delete |
| "As we can see" | Delete |
| "Going forward" | Delete, or specify a timeframe |
| "At the end of the day" | Delete |
What to look for: Sentences that begin with these phrases and contribute nothing after removal. The surrounding sentence remains grammatically correct and retains its meaning.
Before / After
<!-- Before -->
It's worth noting that the connection pool defaults to 10.
<!-- After -->
The connection pool defaults to 10.# Before
# This allows us to gracefully handle timeout errors
# After
# Handles timeout errors with exponential backoff<!-- Before (commit message) -->
Going forward, all API responses will include pagination metadata.
<!-- After -->
All API responses now include pagination metadata.fix_safety: Safe -- these phrases can be removed mechanically without changing meaning.
---
Excessive Hedging
Overuse of qualifiers that weaken technical statements. In technical documentation, either something is true or it is not. Stacking hedges signals that the author (or model) is uncertain about claims that should be definitive.
What to look for: Multiple hedging words combined in a single clause, or hedges applied to verifiable facts.
Common patterns:
- "might potentially" -- pick one or neither
- "could possibly" -- pick one or neither
- "it seems like it may" -- state what it does, or document the ambiguity explicitly
- "arguably" -- either make the argument or remove the claim
- "one could say" -- say it or remove it
- "it is generally considered" -- by whom? cite or state directly
- "this should theoretically" -- test it and state the result
Before / After
<!-- Before -->
This approach might potentially reduce latency in some cases.
<!-- After -->
This approach reduces p95 latency by ~40ms in benchmarks (see #214).<!-- Before (PR description) -->
The refactor could possibly improve readability and arguably makes
the module easier to test.
<!-- After -->
The refactor separates I/O from parsing, making the module unit-testable
without mocks.# Before
# This should theoretically handle all edge cases
# After
# Handles empty input, None, and negative values (see test_edge_cases)fix_safety: Needs review -- removing hedges changes the strength of the claim. Verify the resulting statement is accurate before committing.
---
Generic Conclusions
Empty summarizing paragraphs that restate what the reader just read. These appear at the end of docs, PRs, and commit descriptions. They add no information and signal AI generation because LLMs are trained on content with formulaic conclusions.
What to look for: Final paragraphs that begin with summarizing phrases and contain no new information, action items, or links.
Common patterns:
- "In conclusion, we have seen that..."
- "To summarize, this document covered..."
- "By following these steps, you will be able to..."
- "Overall, this implementation provides..."
- "In summary, the changes above..."
- "With these changes in place, we now have..."
Before / After
<!-- Before (end of PR description) -->
In summary, the changes above refactor the authentication module to use
JWT tokens instead of session cookies, improving security and reducing
server-side state. By following this approach, we ensure that the system
is more maintainable and scalable going forward.
<!-- After -->
## Migration
Existing sessions expire after deploy. Users will need to re-authenticate.
See the migration runbook: docs/runbooks/auth-jwt-migration.md<!-- Before (end of a doc page) -->
By following these steps, you will be able to deploy your application
to production successfully. We have covered all the necessary
configuration and setup required for a smooth deployment.
<!-- After -->
## Next steps
- [Set up monitoring](/guides/monitoring) for your production deployment
- [Configure alerting](/guides/alerts) for error rate thresholds# Before (end of module docstring)
# In conclusion, this module provides a comprehensive set of utilities
# for handling date parsing across multiple formats.
# After
# Supported formats: ISO 8601, RFC 2822, Unix timestamps.
# See parse_date() for the full format list.fix_safety: Safe -- generic conclusions can be deleted outright. If the section needs a closing, replace it with actionable next steps or concrete references.
Formatting Patterns
Detection criteria for AI-generated formatting habits in developer docs, commit messages, PR descriptions, and code comments.
1. Boldface Overuse
What to Look For
AI tends to bold every key term, creating visual noise that dilutes emphasis. In developer documentation, bold should be reserved for UI element labels, key terms on first introduction, and warnings or critical notes.
Detection Patterns
Bolding common terms throughout a paragraph:
<!-- BAD - Every term is bold, nothing stands out -->
The **server** reads the **configuration file** on **startup** and
initializes the **database connection pool**. If the **connection**
fails, the **retry logic** kicks in with **exponential backoff**.
<!-- GOOD - Bold only on first introduction of a key concept -->
The server reads the configuration file on startup and initializes
the database connection pool. If the connection fails, the retry
logic kicks in with **exponential backoff** (see Retry Strategies).Bolding obvious terms in lists:
<!-- BAD - Bold on every list label adds nothing -->
- **Port**: 8080
- **Host**: localhost
- **Protocol**: HTTP
<!-- GOOD - Plain text when the structure already provides emphasis -->
- Port: 8080
- Host: localhost
- Protocol: HTTPBolding in commit messages or PR descriptions:
<!-- BAD -->
Fix **race condition** in **connection pool** when **timeout** expires
<!-- GOOD -->
Fix race condition in connection pool when timeout expiresfix_safety
Safe. Removing unnecessary bold formatting does not change meaning.
---
2. Emoji Decoration
What to Look For
Gratuitous emoji in technical writing where plain text is clearer. Common in AI-generated changelogs, PR descriptions, commit messages, and documentation headings. Emoji should only appear when they serve a functional purpose (e.g., status indicators in a table).
Detection Patterns
Emoji in changelog or release notes:
<!-- BAD - Emoji adds no information -->
## What's New
- :rocket: Added streaming support for large responses
- :bug: Fixed null pointer in auth middleware
- :sparkles: New CLI flag for verbose output
- :wastebasket: Removed deprecated v1 endpoints
<!-- GOOD - Let the content speak -->
## What's New
- Added streaming support for large responses
- Fixed null pointer in auth middleware
- New CLI flag for verbose output
- Removed deprecated v1 endpointsEmoji in headings or section titles:
<!-- BAD -->
## :wrench: Configuration
## :book: API Reference
## :warning: Known Issues
<!-- GOOD -->
## Configuration
## API Reference
## Known IssuesEmoji as bullet markers or checkmarks:
<!-- BAD - Emoji replacing standard list markers -->
:white_check_mark: Unit tests passing
:white_check_mark: Integration tests passing
:white_check_mark: Linting clean
<!-- GOOD - Use standard markdown -->
- [x] Unit tests passing
- [x] Integration tests passing
- [x] Linting cleanfix_safety
Safe. Removing decorative emoji does not change technical meaning.
---
3. Heading Restatement
What to Look For
The first sentence after a heading restates the heading in slightly different words. This is filler that delays the reader from reaching useful content. The heading already names the topic; the body should immediately provide substance.
Detection Patterns
Restating the heading as a definition:
<!-- BAD - First sentence is the heading in sentence form -->
## Error Handling
Error handling is an important aspect of building robust applications.
When an error occurs...
<!-- GOOD - Jump straight into substance -->
## Error Handling
All functions in this module return `(result, error)` tuples. Check
the error value before using the result.Restating with "This section describes...":
<!-- BAD - Meta-commentary about the section itself -->
## Authentication
This section describes how authentication works in the system.
The authentication flow begins when...
<!-- GOOD - Start with what the reader needs -->
## Authentication
Clients authenticate by sending a Bearer token in the `Authorization`
header. Tokens are issued by the `/auth/token` endpoint and expire
after 24 hours.Restating in code comments:
# BAD - Comment restates the function name
def calculate_retry_delay(attempt: int) -> float:
"""Calculate the retry delay.
Calculates the delay before retrying a failed request.
"""
return min(2 ** attempt, MAX_DELAY)
# GOOD - Comment adds information the name doesn't convey
def calculate_retry_delay(attempt: int) -> float:
"""Exponential backoff capped at MAX_DELAY seconds.
Uses jitter to prevent thundering herd on service recovery.
"""
return min(2 ** attempt, MAX_DELAY)fix_safety
Needs review. The restated sentence sometimes contains useful qualifiers or scope limitations mixed in with the filler. Verify that no meaningful context is lost before removing.
---
Review Questions
1. Does every bold term in this paragraph genuinely need emphasis, or would one or two suffice? 2. Would this changelog entry lose any meaning without the emoji? 3. Does the first sentence after this heading tell the reader something the heading did not?
Vocabulary Patterns
Detection patterns for AI-generated writing in developer docs, commit messages, PRs, and code comments.
1. AI Vocabulary
What to Look For
Words that appear disproportionately in AI-generated text, organized by signal strength.
High-Signal Words (Always Flag)
These rarely appear in natural developer writing. Flag every occurrence.
delve, utilize, leverage (meaning "use"), whilst, furthermore, moreover, harnessing, revolutionize, paradigm, synergy, facilitate, empower, elevate, unleash, robust (non-technical), seamless, cutting-edge, endeavor, pivotal, embark
<!-- BAD -->
Let's delve into how this module leverages the cache to facilitate
seamless data retrieval, empowering developers to unleash the full
potential of the framework.
<!-- GOOD -->
This module uses the cache for faster data retrieval.fix_safety: Safe. Direct word substitution.
Low-Signal Words (Flag in Clusters of 3+)
Normal in isolation, but AI signals when clustered. Flag when 3+ appear in one paragraph.
ensure, enhance, comprehensive, streamline, optimize, implement, innovative, significant, fundamental, essential
<!-- BAD - 4 low-signal words clustered -->
This comprehensive update ensures that the streamlined pipeline
handles all essential edge cases.
<!-- GOOD -->
This update fixes edge case handling in the pipeline.fix_safety: Safe. Rewrite with plain language.
---
2. Copula Avoidance
What to Look For
AI avoids simple copula verbs ("is", "are", "was") and substitutes complex verb phrases. The result is stiff and indirect.
Detection Patterns
Watch for these phrases followed by articles ("a", "an", "the"):
- "stands as" / "serves as" / "acts as" / "functions as" / "remains as" / "exists as"
<!-- BAD -->
This module stands as the primary entry point for authentication.
The `Config` struct serves as the central configuration object.
<!-- GOOD -->
This module is the primary entry point for authentication.
The `Config` struct is the central configuration object.# BAD
# This class serves as a wrapper around the database connection
class DB:
...
# GOOD
# Wraps the database connection
class DB:
...Note: "acts as" is valid when describing adapter/proxy design patterns.
fix_safety: Safe. Replace with "is" or rewrite as a direct statement.
---
3. Rhetorical Devices
What to Look For
AI overuses rhetorical questions and dramatic framing in documentation. Developers write direct statements; AI writes engagement hooks.
Detection Patterns
Rhetorical questions as section openers:
<!-- BAD -->
Ever wondered how to secure your API endpoints? What if you could
add authentication in just a few lines of code?
<!-- GOOD -->
Add authentication to API endpoints using middleware."Imagine" framing:
<!-- BAD -->
Imagine a world where your deployments never fail.
<!-- GOOD -->
The CI pipeline catches failures before deployment.Dramatic introductions:
<!-- BAD -->
In today's fast-paced development landscape, managing state has
become one of the most challenging aspects of building modern
applications. This library was born from the need to...
<!-- GOOD -->
A state management library for React applications.In PR descriptions:
<!-- BAD -->
Have you ever struggled with flaky tests? This PR tackles that
age-old problem by introducing deterministic test ordering.
<!-- GOOD -->
Fix flaky tests by making test ordering deterministic.fix_safety: Safe. Replace with direct statements.
---
4. Synonym Cycling
What to Look For
AI cycles through synonyms for the same concept to avoid repetition. In technical writing, consistency matters more than variety. Call a "function" a "function" every time.
Detection Patterns
Cycling technical terms:
<!-- BAD - same thing called 4 different names -->
The `processOrder` function validates the input. The method then
checks inventory. This procedure calculates the total. Finally,
the routine saves the order to the database.
<!-- GOOD - consistent terminology -->
The `processOrder` function validates the input, checks inventory,
calculates the total, and saves the order to the database.Cycling component names:
<!-- BAD -->
The `UserCard` component renders the avatar. This widget also
shows the username. The element handles click events.
<!-- GOOD -->
The `UserCard` component renders the avatar, shows the username,
and handles click events.In commit messages:
# BAD
Refactor auth module, restructure login flow, reorganize session
handling, and rearchitect token management
# GOOD
Refactor auth module: simplify login, session, and token handlingCommon cycling sets to watch for:
- function / method / procedure / routine
- component / widget / element
- refactor / restructure / reorganize / rearchitect
fix_safety: Needs review. Determine which term is most accurate, then use it consistently.
---
5. Commit Message Inflation
What to Look For
AI turns simple changes into grand narratives. Good commits are terse and specific.
Detection Patterns
Grandiose verbs for small changes:
# BAD # GOOD
Revolutionize the authentication flow Fix auth token refresh
Elevate the user experience Improve error messages
Empower the CI pipeline Add unit tests for authMarketing language in commit bodies:
# BAD
This commit introduces a paradigm shift in how we handle database
connections, leveraging connection pooling to deliver a seamless
and robust experience for all downstream consumers.
# GOOD
Switch to connection pooling. Fixes timeout errors under load.
See #234.Overexplaining obvious changes:
# BAD
feat: Implement the crucial and fundamental addition of a
comprehensive user validation layer that ensures data integrity
# GOOD
feat: add input validation to user signupQuick Reference
| Inflated | Plain |
|---|---|
| "Revolutionize X" | "Fix X" / "Refactor X" |
| "Comprehensive overhaul" | "Refactor" / "Rewrite" |
| "Elevate the experience" | "Improve" |
| "Introduce a paradigm shift" | "Change" / "Switch to" |
| "Ensure robust handling" | "Fix" / "Handle" |
| "Empower users with" | "Add" |
| "Streamline the workflow" | "Simplify" |
| "Leverage cutting-edge" | "Use" |
fix_safety: Safe. Rewrite using Conventional Commits with plain verbs (add, fix, update, remove, refactor).
---
Review Questions
1. Does the text contain any high-signal AI vocabulary words? 2. Are there 3+ low-signal words clustered in a single paragraph? 3. Does the writing avoid simple "is/are" in favor of complex verb phrases? 4. Are there rhetorical questions or "imagine" framing in technical docs? 5. Is the same concept referred to by multiple different terms within a section? 6. Do commit messages use dramatic verbs for routine changes?