Skip to main content
Glama

bot-tells

bot-tells: check a message before you send it, and know if it sounds like a bot

Check a message before you send it for what makes readers think a bot wrote it.

npx @askeleven/bot-tells "I hope this email finds you well. I wanted to reach out..."

Or paste one into the web page: askeleven.github.io/bot-tells. It runs in your browser, and nothing you paste leaves the page.

A reader decides in one line whether a person wrote to them. "I hope this email finds you well" and the message is filed with the other thousand. A [First Name] nobody filled in, or a "Let me know if you'd like me to adjust the tone" left at the bottom, and it is worse: the reader now knows nobody read it before it went out. bot-tells finds those things first. It is a CLI for pipelines, an MCP server so an agent can check its own writing, a library, and a web page. It returns a verdict, a 0-100 bot score, every finding with where it is and what to write instead, and the fixes that are safe to make without a rewrite.

Zero dependencies. No signup, no account, no network.


Not an AI detector

bot-tells cannot tell who wrote a message, and does not try. People write every one of these phrases too. It finds what a reader would hold against the message, whoever wrote it. A person who opens every email with "I hope this finds you well" gets the same score as a model that does, and should hear the same advice.

Related MCP server: Natural Voice MCP

What it checks

Leaks are chat output that should never reach a reader. Any leak fails the message, whatever the score.

Leak

Example

Placeholder left in

[First Name], [Insert link], {{ company }}, <Your Name>

The model talking about itself

"As an AI language model", "my training data"

Chat wrapper at the start

"Sure! Here's a draft of the email:", a Subject: line in the body

Chat wrapper at the end

"Let me know if you'd like me to adjust the tone", "Feel free to customize this template"

Markdown that will not render

**bold**, ## Heading, [link](https://...) in an email, SMS or post (--markdown turns this off for Slack and GitHub)

Tells are wording readers now associate with bots. They add to the score; none of them decides anything alone.

Tell

Example

Stock openers

"I hope this email finds you well", "I wanted to reach out", "Great question!"

Stock closers

"Don't hesitate to reach out", "I hope this helps", "I'd be happy to help"

Stock phrases

"In today's fast-paced world", "navigate the complexities of", "a testament to", "unlock your full potential"

Words people now read as AI

delve, tapestry, pivotal, seamless, leverage, utilize, moreover, and about 35 more

"Not X, but Y"

"It's not just a tool, it's a game-changer"

Rhetorical reveals

"The result?" "The best part?"

Customer-service sycophancy

"You're absolutely right", "I apologize for any inconvenience"

Em dashes

People use them well. Readers now count them anyway.

Emoji bullets, from two lines up

The house style of generated posts

Exclamation marks, from three up

Enthusiasm at a steady rate

Every rule is in src/data/rules.js, with its weight and the reason for it.

The score

Each finding has a weight from 1 (people say it all the time; it only counts in company) to 6 (almost nobody types this by hand any more). Repeats of the same thing count for less each time, and past a cap for nothing. The points become a score from 0 to 99 on a curve scaled by length, because one stock phrase says more about a three-line email than about a long one: one "I hope this email finds you well" in a 60-word email is 39.

Keep below 25. Review from 25: a reader may notice. Fail from 60, or on any leak. Both thresholds are options.

What it does not do

It does not rewrite. --fix makes only the changes that need no judgement: it cuts a filler sentence when the sentence is nothing but filler, cuts chat wrappers, swaps a few words one for one (utilize to use, a myriad of to many), turns a pair of em dashes around an aside into commas, and unwraps Markdown. "Please don't hesitate to contact me on 305-555-0100" stays, because cutting it would cut the number. The rest is listed for a person, or a model, to rewrite with the suggestion beside it.

It only reads English.

It does not know your reader. "I hope you're well" to a friend is warm. The score is about strangers.


Example

$ npx @askeleven/bot-tells draft.txt

FAIL  Reads like a bot wrote it.

      Bot score    83/100  [#################---]
      Length       90 words, 11 sentences
      Found        8 tells

   3  >>I hope you're doing well<<! I wanted to follow up on our conversation last week regarding the website redesign. Our team has >>delved<< into your requirements and put together a >>comprehensive<< proposal that addresses your key goals >>—<< faster load times, a cleaner layout, and better mobile support.
   5  >>The result?<< A site that >>not only looks great but also<< converts. We believe this will >>play a pivotal role in<< your growth.
   7  >>Please let me know if you have any questions<<. I look forward to hearing from you!

TELLS
  Words people now read as AI
      Real words, but ones language models use far more than people do, so
      readers have learned to spot them. "delved" (line 3): Try "look at",
      "dig into". "comprehensive" (line 3): Try "full", "complete".
  Rhetorical reveal
      "The result?" (line 5). "The result?" "The best part?" A question
      asked only to answer it in the next breath. Make it a statement: "It
      cut onboarding to two days."
  ...

In a terminal the findings are highlighted rather than marked with >> and <<.

$ npx @askeleven/bot-tells draft.txt --fix > fixed.txt
Fixed 2 of 8. Score 83 -> 77/100 (fail). 6 findings left for a person.

Options

--fix                 Print the message with the safe fixes applied, and a
                      summary on standard error.
--markdown            The destination renders Markdown (Slack, GitHub), so
                      Markdown is not a leak.
--ignore <list>       Codes or rule ids to skip, comma-separated, such as
                      em_dash,exclamations.
--review-at <n>       Review at this score or above. Default 25.
--fail-at <n>         Fail at this score or above. Default 60.
--json                Machine-readable output.
--no-colour           Plain text.

The message is the text on the command line, a file, or standard input (-, or piped in with no text).

Exit code 0 means OK to send, 1 means do not send it as it stands (a leak, or the score is at --review-at or above), 2 means it could not run. So it gates a pipeline:

npx @askeleven/bot-tells reply.txt && ./send reply.txt

For agents: MCP server

npx @askeleven/bot-tells mcp

It serves two tools over stdio: check_message (the verdict, score and findings) and fix_message (the text with the safe fixes applied, what was applied, and what is left to rewrite). The server tells the model never to send a message with a leak, to apply the safe fixes, to rewrite what is left in plain words rather than swap one stock phrase for another, and to check again.

Claude Code

claude mcp add bot-tells -- npx -y @askeleven/bot-tells mcp

Claude Desktop, Cursor, and other clients that take a JSON config:

{
  "mcpServers": {
    "bot-tells": {
      "command": "npx",
      "args": ["-y", "@askeleven/bot-tells", "mcp"]
    }
  }
}

As a library

import { checkMessage, fixMessage } from '@askeleven/bot-tells'

const result = checkMessage(draft)
if (result.verdict !== 'keep') {
  const { text, unfixed } = fixMessage(draft)
  // unfixed: findings with line, column, text and suggestion, for a rewrite
}

checkMessage(text, options) takes reviewAt, failAt, markdown and ignore. It returns verdict, score, summary, reasons (one per kind, with a stable code to match on and a detail to show a person) and findings (each with start and end offsets, line, column, the text as written, and a suggestion).

fixMessage(text, options) returns the fixed text, applied, unfixed, and result, the fixed text checked again.

The library has no Node-only imports, so it runs in a browser as is: the web page imports the same src/index.js.

Privacy

Nothing leaves your machine. There is no network code. The web page is static, loads no fonts, scripts or analytics from anywhere else, and the score card it makes is drawn in your browser.

Requirements

Node 20 or newer. No dependencies.


Why we built it

AskEleven runs AI employees that email and text candidates and customers for small businesses. A message from one of them has to read like it came from the business, because to the person receiving it, it did. This is the check for how it reads, run before anything is sent.

Contributing

Issues and pull requests welcome, especially:

  • False positives. A normal sentence a person would write that bot-tells holds against them. Include the sentence. These matter more than anything else here.

  • Tells we miss, with two or three real examples. A phrase only gets in if people outside this repo already read it as a sign of a bot.

  • Weights that look wrong.

  • Other languages. The rules are English only.

Run the tests with npm test, and build the web page into _site/ with npm run build:site.

License

MIT. See LICENSE.

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    Not graded
    maintenance
    Provides tools and resources to detect AI-generated writing patterns and refine text for more authentic, human-like communication. It enables users to analyze phrasing via a scoring system and apply conversational guides tailored for platforms like Twitter and LinkedIn.
    1
    -
  • A
    license
    Not graded
    quality
    B
    maintenance
    Provides writing guidance and mechanical lint checks to help AI clients draft or rewrite content in a specific natural voice.
    MIT
  • F
    license
    Not graded
    quality
    A
    maintenance
    Enables agents to analyze text or files for formulaic AI writing patterns, returning a 0–100 score, band label, violations with context, and advice. It uses configurable rule-based heuristics without LLM judges or API calls.
    -
  • F
    license
    Not graded
    quality
    A
    maintenance
    Enables agents to analyze prose for formulaic AI writing patterns and return scores, band labels, violations, and improvement advice. Supports checking inline text or files through MCP tools without external LLM or API calls.
    -