Your prompt won't fix AI-sounding writing. A lint rule will.
I generate a fair amount of technical writing with models. For a long time I kept getting the same reaction from readers, and it took me too long to name it properly.
The posts were not wrong. They were tiring.
The failure had a shape. A section would open by announcing why the topic mattered before it said anything about the topic. A list would arrive as a column of bold labels, each followed by a colon and a restatement of the label. A section would end by hedging — "it is worth keeping in mind that..." — and commit to nothing.
None of that is a factual error. All of it is a reason to stop reading at paragraph three.
The prompt approach, and why it kept slipping
My first move was the obvious one. I described the problem to the model and asked it to stop.
So the system prompt grew. Do not open with a definition. Vary sentence length. Skip the three-item lists. Do not end on a vague note.
It held for a few days. Then it drifted back, and I could never tell exactly when.
The reason is structural. A prompt is a request, and requests get weighed against everything else the model is doing, on every token. There is no moment where the instruction passes or fails. Nothing is measured, so nothing stays fixed. I was negotiating with a system that had no memory of the negotiation.
There is a second problem, subtler. Style instructions in a prompt compete with each other. "Be concise" and "be thorough" both get weight. "Avoid lists" fights "be scannable." The model resolves that tension silently, differently on different days. You see the average of the conflict, never the conflict itself.
What a linter does differently
A linter flips the relationship. It does not ask for anything. It reads finished text and returns violations.
The property that matters: a linter can go red. That is a state a prompt cannot reach.
For English prose the tool I would start with is Vale. Single binary, MIT licensed, understands Markdown well enough to skip code blocks, and runs offline with no account.
Install it, then drop a .vale.ini at the repo root:
StylesPath = .vale/styles
MinAlertLevel = warning
[*.md]
BasedOnStyles = Vale, write-good
Run it against a directory of drafts:
vale articles/
If you want patterns aimed specifically at machine-written prose rather than general wordiness, there are community style packages for that. They tend to target the tells rather than any single word: participial padding ("...thereby ensuring that..."), contrastive negation used as a reflex ("not X, but Y"), and lead-ins that forecast a count ("there are three things to consider here") before delivering two.
Which package you pick matters less than the fact that the rule is written down once, runs identically every time, and produces a number you can look at.
Where you put the gate matters more than what is in it
This is the part I got wrong first.
I had a linter. I ran it manually, when I remembered to. Which meant I ran it maybe half the time.
A gate that depends on you remembering to open it is not a gate. It is a suggestion with extra steps.
So it goes on the publish path. For a GitHub-based flow, that is a workflow that runs on every push:
name: prose-gate
on:
push:
branches: [main]
pull_request:
jobs:
vale:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: errata-ai/vale-action@reviewdog
with:
files: all
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
Now the text cannot reach a publishable state while it is failing.
One caveat I learned the hard way, and it is worth stating plainly: on some platforms the CI job and the actual deploy are completely separate systems.
I run a similar gate for Japanese articles on Zenn. Zenn deploys by watching pushes to the branch directly. A red CI check does not stop it, does not delay it, and does not warn anyone. It is a separate set of lights on a separate wall.
If your platform deploys outside CI, your CI gate is a notification, not a gate. The thing that actually blocks publication is the run that happens locally, before you commit. Check which one you have before you trust either.
Do not trust the style guide. Measure your corpus.
Here is the finding that changed how I write rules.
I was setting up a Japanese prose gate and hit a rule about spacing between full-width and half-width characters. The official style guide for Japanese technical writing says: do not add the space.
Before writing that into the config, I pulled the ten most-liked Japanese posts on the platform and counted. 78% of them added the space.
The official guide and the most-read actual writing disagreed, and not by a narrow margin.
I turned the rule off and followed the corpus. Not because the guide was wrong in principle, but because a rule that fights the audience's reading habit is a rule that makes your writing feel foreign — which was the exact problem I was trying to solve.
The general version: a style guide is a hypothesis about your readers. Your readers' own most-liked writing is evidence. When the two conflict, look at the evidence, then decide. Do not let a document win an argument against data.
This is also why I keep the rule config in the same repo as the articles. The rules are part of the content, and they should change when the corpus tells you to. A linter config that nobody revisits is a linter config that slowly becomes wrong.
What the linter cannot do
I want to be careful here, because this is easy to oversell.
A prose linter checks the shape of your writing. It does not check whether the writing is true.
Those are separate gates and you need both. The AI-content guidelines on both dev.to and Zenn are explicit that AI-assisted work has to be fact-checked before it goes out. No linter will do that for you. The smell of machine-written prose and the accuracy of a claim are independent axes, and passing one tells you nothing about the other.
It also cannot tell you whether the piece should exist. A clean lint run on an article nobody needed is still an article nobody needed.
The short version
- A prompt is a request. It drifts, and you cannot see it drift.
- A lint rule is a gate. It is deterministic and it can fail.
- Put the gate where publishing actually happens. If your platform deploys outside CI, that is your local pre-commit run.
- Write your rules from your own corpus. An official guide can be wrong about your readers.
- The gate covers style. Facts are a different gate, and you still need it.
I still use prompts. I just stopped expecting them to be the thing that holds.
This article was written by a human and edited with AI assistance. The lint guidance described here was applied to this draft as well — the irony of shipping a piece about AI-sounding prose without running it through a gate was not lost on me.