mech.app

The mech.app newsletter

Agentic AI, minus the noise.

Get practical field notes on AI agents, automation, developer tools and security delivered to your inbox.

No spam. Unsubscribe anytime.

Dev Tools

No AI Slop: How a 20-Pattern Linter Strips LLM Fingerprints Without Flattening Your Voice

A skill-based editing tool that removes AI writing patterns while preserving personal voice, exposing the tension between automated editing and authoria...

Source: github.com
No AI Slop: How a 20-Pattern Linter Strips LLM Fingerprints Without Flattening Your Voice

AI-generated text has a fingerprint. You know it when you see it: binary contrasts (“It’s not X. It’s Y.”), throat-clearing openers (“Here’s the thing”), faux-insight setups (“What nobody tells you”), and dramatic fragments that land like wet cardboard. The problem is not that AI writes poorly. The problem is that AI writes the same way every time, and when you use it to edit your own work, it smooths away the vocabulary, cadence, and imperfections that make writing sound like you.

No AI Slop is a skill-based linter that detects 20+ patterns of LLM-generated prose and removes them without flattening your voice. It hit 8,616 stars in days and trended #8 on GitHub Python because it solves a real pain point: you want the speed of AI editing, but you do not want your blog posts to sound like every other GPT-4 output on the internet.

The interesting part is not the pattern list. The interesting part is the architecture: this is a skill, not a script. It runs inside coding agents (ChatGPT, Claude Code, Codex) as a deterministic, inspectable ruleset. That raises a question most agent tooling ignores: what happens when you want version-controlled, testable editing logic instead of opaque LLM rewrites?

What It Detects

No AI Slop checks for 20+ patterns, including:

  • Binary contrasts. “It’s not X. It’s Y.”
  • Throat-clearing openers. “Here’s the thing,” “Let me be clear”
  • Faux-insight setups. “What nobody tells you,” “The part everyone misses”
  • Colon reveals. “The best part: it learns.”
  • Dramatic fragments. “That’s it. That’s the whole thing.”
  • Superficial analysis. “highlighting the team’s commitment to innovation”
  • Importance puffery. “marks a pivotal moment,” “a marker of”
  • Weasel attribution. “experts agree,” “studies show”
  • Synonym cycling. “The agent handles your email. The assistant drafts replies.”
  • Fake-profound endings. “The future isn’t coming. It’s already here.”

It also checks fundamentals: lead with the point when that helps, use active voice, untangle hard-to-follow sentences, prefer concrete details over abstractions.

The tool does not guess whether AI wrote the text. It quotes every slop pattern it found and lists what it changed. That makes it auditable.

Skill-Based Architecture

No AI Slop is distributed as a skill, not a standalone CLI. You install it by pasting a command into ChatGPT, Claude Code, or another coding agent:

Install the /no-ai-slop skill globally from https://github.com/petergyang/no-ai-slop

Or via npx:

npx skills add petergyang/no-ai-slop --skill no-ai-slop --global --yes

Once installed, you invoke it with:

/no-ai-slop (your writing)

The agent reads the skill definition, applies the rules, and returns edited text with a changelog.

This is different from traditional linting in three ways:

  1. The skill is a prompt, not a binary. The ruleset lives in SKILL.md, a Markdown file that describes the editing workflow in natural language. The agent interprets it at runtime.
  2. The skill is testable. eval.md contains test cases with input text and expected edits. You can run the skill against the eval suite to verify behavior.
  3. The skill is version-controlled. You can fork it, modify the patterns, and distribute your own variant. The agent pulls the skill from GitHub, so updates propagate automatically.

This is a different boundary than most agent tools. Instead of exposing a function signature (input string, output string), you expose a natural-language contract that the agent must interpret. That gives you flexibility (you can describe complex editing logic without writing code), but it also introduces ambiguity (the agent might not interpret the rules the way you expect).

What Happens Inside the Agent

When you invoke /no-ai-slop, the agent performs a multi-step workflow:

  1. Load the skill. The agent fetches SKILL.md from the repo and parses the editing rules.
  2. Scan the input. The agent reads your text and checks for each pattern in sequence.
  3. Apply edits. For each match, the agent rewrites the sentence according to the rule. It does not just delete the pattern. It restructures the sentence to preserve meaning.
  4. Generate a changelog. The agent lists every change it made, quoting the original text and the replacement.
  5. Return the result. The agent outputs the edited text and the changelog.

This workflow is deterministic in principle (the rules are explicit), but non-deterministic in practice (the agent must interpret natural-language instructions). That creates a tension: you want the skill to behave like a linter (same input, same output), but it behaves more like a code review (same input, different suggestions depending on the agent’s interpretation).

Tool Boundaries and Agent Respect

The skill-based architecture raises a question: does the agent respect the edits, or does it reintroduce slop in the next iteration?

If you use No AI Slop inside a coding agent, the agent sees the edited text as the new baseline. But if you ask the agent to continue editing (for example, “make this more concise”), it might reintroduce the same patterns. The agent does not remember that you already stripped the slop. It only sees the current state of the document.

This is a tool boundary problem. The skill is stateless. It does not track what it has already fixed. If you want to prevent slop from creeping back in, you need to:

  • Run the skill as a final pass. Edit your text with the agent, then run /no-ai-slop as the last step before publishing.
  • Combine it with a linter. Use a traditional linter (like Vale or textlint) to enforce the same rules in CI. That way, if the agent reintroduces slop, the linter catches it.
  • Version the skill with your project. Fork the skill, add project-specific patterns, and lock it to a commit hash. That way, the agent always uses the same ruleset.

Testing and CI/CD for Agent Skills

No AI Slop includes eval.md, a test suite with input text and expected edits. This is unusual for agent tools. Most agent skills are untestable closed boxes. You invoke them, you get a result, and you have no way to verify correctness except by reading the output.

The eval suite changes that. You can run the skill against the test cases and check whether the output matches the expected edits. This makes the skill auditable and version-controllable.

But it also raises a question: how do you run the eval suite in CI?

The skill does not ship with a test runner. You cannot run npm test or pytest and get a pass/fail result. Instead, you have to:

  1. Invoke the agent programmatically. Use the agent’s API (for example, OpenAI’s Chat Completions API) to send the skill and the test input.
  2. Parse the output. Extract the edited text and the changelog.
  3. Compare against expected output. Check whether the edits match the expected changes in eval.md.

This is not a standard CI workflow. You are testing a natural-language contract, not a function signature. The agent might produce correct edits that do not match the expected output word-for-word. You need fuzzy matching or semantic similarity checks, not string equality.

Here is a rough sketch of what that looks like:

# Pseudocode: assumes openai library and helper functions are defined
import openai

def load_skill(path):
    """Load skill definition from SKILL.md"""
    with open(path) as f:
        return f.read()

def load_eval(path):
    """Parse eval.md into test cases"""
    # Returns list of dicts with 'input' and 'expected' keys
    pass

def test_no_ai_slop():
    skill = load_skill("SKILL.md")
    test_cases = load_eval("eval.md")
    
    for case in test_cases:
        input_text = case["input"]
        expected_edits = case["expected"]
        
        response = openai.ChatCompletion.create(
            model="gpt-4",
            messages=[
                {"role": "system", "content": skill},
                {"role": "user", "content": f"/no-ai-slop {input_text}"}
            ]
        )
        
        output_text = response["choices"][0]["message"]["content"]
        
        # Fuzzy match: check if expected edits appear in output
        for edit in expected_edits:
            assert edit in output_text, f"Missing edit: {edit}"

This is not a perfect test. The agent might produce equivalent edits that do not match the expected output. But it gives you a baseline: if the agent stops catching a pattern, the test fails.

Trade-Offs: Deterministic Rules vs. LLM Flexibility

No AI Slop exposes a tension between deterministic rules and LLM flexibility. You want the skill to behave like a linter (same input, same output), but you also want the agent to understand context and apply the rules intelligently.

ApproachProsCons
Deterministic linterPredictable, testable, fast. No API calls.Cannot handle context. Misses patterns that require semantic understanding.
LLM-based skillUnderstands context. Can rewrite sentences, not just delete patterns.Non-deterministic. Requires API calls. Might reintroduce slop in later edits.
Hybrid (linter + skill)Linter catches obvious patterns. Skill handles edge cases.More complex. Requires two tools. Linter and skill might conflict.

No AI Slop chooses the LLM-based approach. That gives it flexibility, but it also means you cannot rely on it for strict enforcement. If you need deterministic behavior, you should combine it with a traditional linter.

When to Use It

No AI Slop is useful when:

  • You use AI to draft or edit writing, and you want to strip the generic patterns without losing your voice.
  • You want inspectable, version-controlled editing rules instead of opaque LLM rewrites.
  • You are building agent workflows that include editing steps, and you want to make those steps auditable.

It is less useful when:

  • You need deterministic, repeatable edits (use a traditional linter instead).
  • You are editing code, not prose (the patterns are specific to natural language).
  • You want the agent to rewrite your text from scratch (this tool edits, it does not generate).

Technical Verdict

No AI Slop is a skill-based linter that removes LLM fingerprints from prose. It is distributed as a natural-language contract (SKILL.md + eval.md) that runs inside coding agents. That makes it flexible and version-controllable, but also non-deterministic and harder to test.

Use it when you want to strip generic AI patterns from your writing without flattening your voice. Avoid it when you need strict, repeatable edits (use Vale or textlint instead). If you are building agent workflows that include editing steps, this is a useful reference for how to structure skills as testable, auditable contracts.

The real insight is not the pattern list. The real insight is the architecture: skills as version-controlled prompts, with eval suites and changelogs. That is a different way to think about agent tools. Instead of exposing function signatures, you expose natural-language contracts. Instead of unit tests, you have example-based evals. Instead of deterministic behavior, you have inspectable rules that the agent interprets at runtime.

That is a trade-off. You get flexibility and auditability, but you lose predictability. Whether that trade-off is worth it depends on your use case.