building vodou.

Readers flag LLM-drafted posts by tell density: count yours

Readers on r/AgentsOfAI answered an LLM-style comment with "Okay, Claude." Word bans miss it: measure tells per 1,000 words against your pre-LLM baseline.

Chad Priest / / 5 min read

A comment by u/Extra-Pomegranate-50 in an r/AgentsOfAI thread about agent harnesses got a two-word reply: “Okay, Claude.” A second reader added: “It is just the dumb Claudes we see easily, these posts chill me because of that.” Neither reply touched what the comment argued. The style alone got it dismissed.

I thought a technical subreddit graded the argument first

The comment wasn’t mine. I was in that thread for a different reason: the OP had asked for tips on checkpoints and evals that stay reliable when you switch harnesses, and on 2026-09-20 nobody had answered. I had a reply drafted and queued for it.

Here is what I had wrong. I believed readers in a technical subreddit would check whether a comment was correct before they reacted to how it sounded. Two replies that skipped the argument completely changed my mind, and I kept my reply out of that subthread.

Ban lists count words, and readers count a rate

The standard advice, as in Kompozy’s seven tells, is a banned list: hedges out, em dashes out. Matthew Vollmer’s field guide gets closer, because it puts the signal “in the clustering of them, the density with which they arrive.” One HN commenter described the behavior exactly: humans use the device too, but “we don’t typically do it every other paragraph,” so “I just start skimming and then close the tab.” That reader is estimating a rate.

My own blog pipeline shows what a ban buys. Its draft prompts told the model not to use em dashes, and across the first 11 posts it emitted 66 of them anyway. So I added a scrubber that deletes them after generation. The 85 posts published today contain 3 em dashes in 122,945 words. The ban works for the one character it names. The rhythm stayed, as the counts below show.

Count five tells per 1,000 words

Two of these are structural, which is the part a word list can’t see: tricolons (three items with “and” or “or” inside one sentence) and bold one-line thesis paragraphs. The function strips frontmatter and fenced code, skips anything under 300 words because short samples are noise, and prints a floating-point rate.

tells() {
  for f in "$@"; do
    body=$(awk 'NR==1 && /^---$/ {fm=1; next} fm && /^---$/ {fm=0; next} fm {next}
                /^```/ {code=!code; next} !code' "$f")
    w=$(printf '%s\n' "$body" | wc -w)
    [ "$w" -lt 300 ] && { echo "skip $f ($w words)" >&2; continue; }
    c() { printf '%s\n' "$body" | grep -oiE "$1" | wc -l; }
    dash=$(c '—')
    neg=$(c "(isn't|is not|wasn't|it's not|that's not|not) (just |only )?[^.!?]{1,60}((,|;|:|\.|—) ?(it's|it is|that's|they're)| but)")
    tri=$(c "[a-z-]+( [a-z-]+)?, [a-z-]+( [a-z-]+)?,? (and|or) [a-z-]+")
    bold=$(printf '%s\n' "$body" | grep -cE '^\*\*[^*]+\*\*\.?$')
    vocab=$(printf '%s\n' "$body" | grep -oiwE 'delve|tapestry|seamless|landscape' | wc -l)
    awk -v f="$f" -v w="$w" -v d="$dash" -v n="$neg" -v t="$tri" -v b="$bold" -v v="$vocab" \
      'BEGIN { printf "%5.1f  dash=%d neg=%d tri=%d bold=%d vocab=%d  %s\n", (d+n+t+b+v)*1000/w, d, n, t, b, v, f }'
  done | sort -n
}
tells old-posts/*.md   # written before you had a model
tells drafts/*.md      # written with one

The negation-contrast pattern takes a comma, semicolon, colon, period or em dash before the second clause, and it also catches “isn’t just” and “not only… but”. I checked it line by line:

It's not a cache — it's a ledger.        matched
It isn't just a cache, it's a ledger.    matched
Not only fast but cheap.                 matched
It's not ready, so I waited.             skipped

The tricolon pattern is crude. On my posts it also fires on “sign-in wall, open devtools and look”, which is a list of steps, not a rhetorical triple. I kept it anyway, because the same crude counter runs on both sides of the comparison, and a constant false-positive rate cancels out.

The pass rule needs at least 5 baseline posts

You need at least 5 posts of 300+ words written before you used a model. With fewer, you have no baseline, and any threshold is a guess. With 5 to 19, a draft passes if it scores no higher than your highest baseline post. With 20 or more, it passes at or below the baseline’s mean plus two standard deviations:

tells old-posts/*.md | awk '{s+=$1; q+=$1*$1; n++; mx=$1}
  END {m=s/n; sd=sqrt((q-n*m*m)/(n-1)); printf "n=%d max=%.1f mean+2sd=%.1f\n", n, mx, m+2*sd}'

My numbers: 85 posts top out at 7.6, and this post’s first draft scored 10.2

I don’t have a folder of pre-model posts to point this at, so I ran it on what I do have: the 85 posts my pipeline has published, every one of them model-drafted.

n=85 max=7.6 mean+2sd=6.4

They range from 0.0 to 7.6, with a mean of 2.97 and a standard deviation of 1.71. Tricolons are 257 of the 359 tells. Negation-contrast is 57, bold thesis lines 42, em dashes 3, and the four vocabulary words 0. Three published posts sit above 6.4.

The first draft of this post scored 10.2: four tricolons and one bold thesis line in 489 words. That is the draft the editor sent back. It fails both rules, and that baseline is the pipeline’s own output, which is the wrong bar for a test of whether I sound like me. Even the wrong bar flagged it.

The pipeline that drafted this post still runs a ban list

A model drafted this post, and I’m saying so. Vodou found the r/AgentsOfAI gotcha in my memory, where it had been extracted from a chat automatically and tagged, with no note-taking from me. The pipeline that wrote it still works the old way. A prompt line bans em dashes. A scrubber deletes the ones that get through. A rubric grades the draft, and a redaction gate scans it before Vodou’s own scheduler deploys it. That is the ban list this post argues against, and the numbers above are my case for changing it: the next change is a rubric line that runs this count and holds any draft above the corpus’s mean plus two standard deviations. This revision scores 5.6, under 6.4, and three of its five hits are the post quoting the patterns it counts.

That’s why the product exists. Your memory sits in a local database you own, and nothing leaves until you send it. The Bridge extension carries that same memory into ChatGPT, Claude and Gemini in the browser, and hooks and MCP bring it into your terminal and IDE. The skills and schedules are yours to write and change, and so are the MCP servers.

Vodou is for engineers who are tired of re-explaining themselves to every AI. Start at vodou.ai.