We Built 17 Guards to Catch Every AI Tell on Your Resume. Here's the Code.

George-AdrianFounder & Engineer, ApplyArcFounder of ApplyArc. Software engineer building the AI Career Coach, anti-AI resume guard pipeline, and Kanban tracker that ships to production daily.
Updated
14 min read
The Short Answer· Updated June 2026

Recruiters can smell an AI-written CV. We built guards to strip every tell before they do.

An anti-AI-tell pipeline scans a resume for the fingerprints recruiters and ATS filters flag: stock phrasing, em-dashes, hedge words, and uniform sentence rhythm. ApplyArc runs 17 such guards plus a free ATS scan, so your CV reads human and passes the parser, no signup, no card.

Free ATS scan, 8 secondsPaste your CV. No signup, no card.

⚡ The short version

Tap to read
53% of hiring managers reject obviously AI-generated resumes. I rebuilt the layer that runs after the LLM: 17 deterministic guards that strip em-dashes, kill 'leveraged', block fabricated leadership, and reject hallucinated scope. With line numbers.
📋 Table of Contents

⚡ The short version

Tap to read
53% of hiring managers reject obviously AI-generated resumes (ResumeGenius, 2026). Every other AI resume tool I tested shipped raw model output: em-dashes everywhere, "leveraged" in half the bullets, fabricated leadership claims, and invented project names. So I rebuilt the layer that runs after the AI. 17 deterministic guards, every rewrite, every time. Em-dashes get stripped. "Leveraged" gets caught. A rewrite that promotes "Helped" to "Led" with no metric is rejected entirely. The code is open in this post, with line numbers.

Ready to put this into practice?

**Try the bullet rewriter free**, no signup. 4 modes. The same guards run on every output.

The 53% Problem

A 2026 survey by ResumeGenius asked hiring managers what they do when a resume looks AI-generated. 53% reject it on sight. Not "score it lower." Reject it.

That number scared me more than any competitive threat. It means the AI-resume product category has a load-bearing assumption baked into it that nobody talks about: the bullets you generate need to not look like bullets you generated.

So I did what any founder paranoid about user outcomes would do. I generated 10 bullets each, on five competitor tools, and counted the tells.

Here is what I found in February 2026 (methodology at the end of this post so you can replicate it):

ToolEm-dash rate"Leveraged" / "Spearheaded" / "Utilized"Fabricated leadership verbs
TealCompare →38%4 of 102 of 10
ReziCompare →41%3 of 101 of 10
Resume WordedCompare →33%5 of 103 of 10
EnhancvCompare →47%4 of 102 of 10
KickresumeCompare →29%6 of 101 of 10

These are the cheap tells. The ones a hiring manager spots in two seconds. Em-dashes in parallel constructions ("Built X, optimized Y, scaled Z") and the small family of consultant verbs that LLMs default to. The shape of an AI-generated bullet is so consistent that recruiters have started turning it into a meme on LinkedIn.

I am not picking on those tools. They are good products. They ship the LLM output because shipping the LLM output is what most "AI resume builder" companies in 2026 are doing. The LLM is the feature. The cleanup is an afterthought.

I want to make the case that the cleanup is the feature.

What an AI tell actually is

Before I show the code, let me name the four patterns that get a resume flagged. These are the ones recruiters spot. They are also the four patterns the guards in this post catch.

1. The em-dash

The em-dash is the single highest-confidence AI fingerprint on a resume. ChatGPT and Claude both default to it in parallel constructions because their training data is full of editorial prose, where em-dashes are common. Resumes are not editorial prose. Humans writing resumes use commas, semicolons, and full stops. They almost never reach for an em-dash, and certainly not three of them in one bullet.

If a recruiter sees this:

Built and shipped a payments platform, owned the migration from legacy infra, and partnered with compliance, with measurable lift across reliability metrics.

That is human-shaped writing. Commas. A confident structure. Adverbs are scarce.

If they see this:

Built and shipped a payments platform, owned the migration from legacy infra, and partnered with compliance, with measurable lift across reliability metrics.

That is the same sentence after our guards have rewritten it. The original (model output) had three em-dashes. We replaced every one with a comma.

2. The consultant verb family

LLMs lean on a small bench of verbs that signal "I am being formal" without committing to anything. The worst offenders, in order of how often I have seen them surface in raw model output during the last 12 months of testing:

  • leveraged
  • spearheaded
  • utilized
  • orchestrated
  • streamlined (when used as a vague replacement for any improvement verb)
  • meticulously
  • pivotal
  • crucial
  • holistic

None of these are bad words in isolation. The problem is statistical. Real resumes use these words at maybe a 2% rate. LLM resumes use them at a 40%+ rate. That density gap is what a recruiter feels even if they cannot name it.

3. Fabricated leadership

This is the dangerous one. The other tells are cosmetic. This one is a lie.

If your original bullet says "Helped the team migrate to React 18" and the LLM rewrites it to "Led the migration to React 18", you are now claiming on your CV that you led work you helped with. In an interview, that gap shows up in the first follow-up question and the interviewer is now wondering what else is inflated.

The model does this constantly. It is trained on a reward signal that prefers confident verbs. "Led" rates higher than "Helped" on every quality benchmark used to train modern LLMs. The model is doing what it was rewarded to do. The product layer above the model needs to stop it.

4. Hallucinated scope

The fourth tell is harder to catch and more damaging when missed. The LLM invents proper nouns. The original bullet says "Built a tool for the compliance team." The rewrite says "Built ComplianceHub for the Risk and Surveillance Operations team."

ComplianceHub does not exist. The Risk and Surveillance Operations team does not exist in your former employer. You did not write it. The model did, because it has been trained to make resumes sound impressive, and proper nouns make resumes sound impressive.

A recruiter doing 30 seconds of background research on a candidate spots this immediately. So does any internal recruiter at the company you used to work for, the moment they cross-check.

Stop losing track of applications

ApplyArc tracks everything automatically, for free.

Try Free Tracker

How we built the guard layer

The full implementation is at job-board-backend/common/ai-tools/helpers/bulletRewriteGuards.js in our codebase. 1,453 lines. 17 sequential passes. Every rewrite the product serves runs through the same pipeline before a user sees it.

I am going to walk you through the structure, then go deep on the four guards that catch the four tells above.

The orchestrator

The entry point is one function:

function applyRewriteGuards(original, rewrite, opts = {}) {

if (!rewrite || typeof rewrite !== "string" || rewrite.trim().length === 0) {

return { ok: false, reason: "empty-rewrite", cleaned: null };

}

const cleaned = stripDashes(killAIVerbs(rewrite)).trim();

// ... 16 more passes ...

return { ok: true, cleaned };

}

The contract is plain. You pass in the original bullet, the AI-generated rewrite, and a small options bag (job description, seniority hint, the user's actual facts). You get back either:

  • { ok: true, cleaned }, the rewrite passed, here is the cleaned version
  • { ok: false, reason }, the rewrite failed for this reason

The reason string is structured. If it begins with one of 18 specific prefixes (leadership-fabrication, scope-hallucination, verb-weaken, etc.), the rewrite is destructive. We do not show it to the user. Not a softened version. Nothing. The original stays.

If it begins with a non-destructive prefix (a minor padding issue, a readability blip), we surface the cleaned version anyway and log why the original AI output was nudged.

That distinction is the whole product. Most LLM products either ship every output or ship the AI-cleaned output. We ship the cleaned output when it is safe, and suppress the output entirely when it is unsafe. The user never sees the lie.

Guard 1: The em-dash strip

Em-dashes are not flagged or scored. They are removed. Deterministically. Before any other pass runs.

// Em-dashes are the #1 AI fingerprint (Claude/GPT default punctuation in

// parallel constructions); 53% of hiring managers reject obvious-AI resumes

// (ResumeGenius 2026). Convert to commas, safe, never lossy.

const cleaned = stripDashes(killAIVerbs(rewrite)).trim();

stripDashes converts every to a comma. killAIVerbs swaps the worst-offender consultant verbs in-place using a shared lexicon (shared/aiTells.json, single source of truth for both the frontend audit display and the backend guards).

Then a second pass catches survivors. Sometimes the model preserves a banned verb inside a scare-quote or negation: "without leveraging cross-team synergies", "avoiding the leveraged wording". The single-token replacement cannot see those. So:

const tellHit = cleaned.match(AI_TELL_LITERALS_RE);

if (tellHit) {

return {

ok: false,

reason: ai-tell-literal-survived:${tellHit[1].toLowerCase()},

cleaned: null,

};

}

If the banned word survives in any form, the rewrite is rejected outright. The reason prefix ai-tell-literal-survived is on the destructive list. The user sees the original.

Guard 2: Verb strength survived

The model is allowed to rewrite. It is not allowed to weaken your verb.

If the original starts with "Built", the rewrite cannot start with "Worked on". If it started with "Owned", the rewrite cannot drop down to "Helped with". This is the verbStrengthGuard function.

The check uses three lists:

  • POWER_VERBS, a curated set of high-impact action verbs
  • DOWNGRADE_VERBS, the contributor-shaped verbs that signal "I was on the team" not "I drove this"
  • PRESERVED_LEAD_VERBS, verbs that should not be promoted even if technically softer (Translated is right for an i18n engineer; do not let the model turn it into Architected)

The guard parses the first semantic word of the rewrite, skipping leading articles and modifiers. If the rewrite starts with "Successfully led", it does not get credit for "led", because "successfully" is itself an AI tell (Guard 10 catches this separately). It gets parsed at "led".

If the lead-verb tier drops compared to the original, the rewrite is rejected. Reason prefix: verb-weaken or verb-downgrade. Both destructive. Both suppress the rewrite entirely.

Guard 3: Leadership fabrication blocked

This is the guard I am proudest of, because this is the one that prevents a real lie reaching your CV.

The rule, plain English: if the original bullet starts with a collaborative verb ("Helped", "Supported", "Assisted", "Worked on", "Contributed to") AND there is no outcome metric (no number, percentage, currency), then the rewrite may not swap that to a leadership verb ("Led", "Drove", "Owned", "Spearheaded", "Architected").

function leadershipFabricationGuard(original, rewrite) {

if (!startsWithCollab(original)) return { ok: true };

if (hasOutcomeMetric(original)) return { ok: true };

if (!startsWithLeadership(rewrite)) return { ok: true };

return { ok: false, reason: "leadership-fabrication" };

}

The escape hatch is the metric. If the rewrite earned the leadership verb by adding a real number ("Led migration of 12 services to cut latency 40%"), the guard lets it through. No metric, no leadership swap. Period.

In production, this guard fires roughly 4% of the time the user clicks "rewrite". One in every 25 rewrites attempted to silently upgrade contribution to leadership. We caught all of them.

We back this up with three more layered guards because the model has learned how to dodge a single check:

  • paletteViolationGuard catches "Managed X" being swapped to "Led X" or "Drove X" without new evidence.
  • gerundPromotionGuard catches "Built X" being wrapped as "Led the build of X" (the same lie in a noun phrase costume).
  • doerToLeadershipGuard catches the bare "Built X to Led X" swap with no earned metric.

Four guards on one failure mode. Each one catches a real bypass pattern I have seen in live model output during audits.

Guard 4: Scope hallucination rejected

The last of the four cardinal tells. The model invents proper nouns to make your work sound bigger than it was.

function scopeGuard(original, rewrite, jobDescription, userFactsText) {

const originalNouns = properNounSet(original);

const rewriteNouns = properNounSet(rewrite);

const allowed = new Set([

...originalNouns,

...properNounSet(jobDescription || ""),

...properNounSet(userFactsText || ""),

]);

const invented = [...rewriteNouns].filter((n) => !allowed.has(n));

if (invented.length > 0) {

return { ok: false, reason: scope-hallucination:${invented[0]} };

}

return { ok: true };

}

The guard extracts proper nouns and unique entities from the original bullet, the job description, and any user-supplied facts. Any proper noun in the rewrite that does not exist in that allowed set is flagged. The reason prefix scope-hallucination is destructive. The rewrite is dropped.

Original: "Worked on data quality dashboards."

Bad rewrite: "Led retail operations data quality at HSBC."

"retail operations" was not in the source. "HSBC" was not in the source. Both invented. Rejected.

This is the guard that prevents you from having a difficult conversation with a reference check.

The other 13 passes

The four tells above are what recruiters notice consciously. The other 13 passes catch the patterns recruiters notice unconsciously. The patterns that make a resume read as "off" without anyone being able to say why.

Quick tour:

PassGuardWhat it stops
1cmeta-commentary"Removed the leveraged wording" written into the bullet itself
3paddingRewrite added words without adding new information
3bover-length capBullets above 32 words that wrap to 3+ lines on a standard template
4bbody-fluffVague tails ("by changing how we handled X")
4cbody-weak-verbHedge verbs in the second clause ("and backed workforce growth")
4dbody-adverb"Proactively", "seamlessly", "successfully" anywhere in the bullet
4ereadabilityFlesch-Kincaid density spike vs the original
5bpalette violation"Managed" upgraded to "Led" with no new evidence
5cgerund promotion"Built X" upgraded to "Led the build of X"
5dorigin fabrication"Translated" upgraded to "Architected" (different authorship claim)
5edoer-to-leadershipBare "Built X" to "Led X" swap
6seniority fabricationJunior bullets using exec verbs, or vice versa
6bvariant integrityAcross multiple rewrites, no two are duplicates, no rewrite is a noop

Each of these was added because I saw the failure mode in real production output. The guards are reactive, on purpose. I do not add a guard I cannot point at a real instance of.

Still reading? Your resume might be the problem.

75% of resumes fail ATS scans. Fix that first, then pick the right tool.

Get free ATS score, then decide

Why nobody else does this

I cannot prove competitors do not do this. What I can say:

  1. None of Teal, Rezi, Resume Worded, Enhancv, or Kickresume publish a guard pipeline like this. Open-source they could share, methodology papers they could write, blog posts like this one they could write. None exist.
  1. The output I tested in February 2026 had em-dash rates between 29% and 47%. A working em-dash stripper would have produced 0%. The math is conclusive on that one specific check.
  1. Building the guard layer is expensive. bulletRewriteGuards.js is 1,453 lines. It took me four months and required four production audits to build the failure-case library it operates on. The cost is engineering time, not API spend. The reward is reputational. Most LLM-first products are racing on feature velocity. Building guard layers does not show up in the demo.
  1. The incentive structure inside an AI resume company also pushes the other way. The team measures "rewrites generated" not "rewrites suppressed". Suppression looks like product failure from inside the building. From outside the building, it is the entire value.

I will steelman the other side. If you are running Teal or Rezi, you might reasonably argue:

  • Most users will edit the output anyway, so polishing it adds cost for little benefit.
  • A guard that suppresses output is a worse user experience than one that ships with a warning.
  • Em-dash detection by recruiters is anecdotal; the data is patchy.

I disagree with all three. The 53% rejection stat is from a recruiter survey, not anecdote. Users who edit their AI output back into something human have to know what an AI tell looks like, and most users do not. Suppression is a worse demo. It is a better product.

But you should hear the other side, because I am the one with the position.

Stop losing track of applications

ApplyArc tracks everything automatically, for free.

Try Free Tracker

How to verify any of this yourself

You do not have to trust me.

Test 1, em-dash audit. Open any AI resume tool. Generate 10 bullets. Copy the output into a text editor. Search for . Count the results. Divide by 10. That is the tool's em-dash rate. We are at 0%. The competitors I tested were between 29% and 47%.

Test 2, leveraged audit. Same procedure. Search for the strings leveraged, spearheaded, utilized. Divide. Same comparison.

Test 3, leadership fabrication. Take a bullet that starts with "Helped" or "Supported" and has no numbers. Paste it. Ask the tool to rewrite it. If the output starts with "Led", "Drove", or "Owned", the tool just put a lie on your CV. Repeat 10 times. Count.

Test 4, scope hallucination. Take a vague bullet ("Worked on tooling for the platform team"). Paste it. Look at the rewrite for proper nouns or specific product names that you never wrote. Count.

I have no way to enforce that you do this audit. I am asking you to do it because the audit will tell you something I cannot tell you, which is whether the tool you currently trust is shipping a version of your CV that has been silently inflated.

What this lets us do that competitors cannot

The guard layer is a substrate. Once you have it, you can stop being afraid of the LLM and start asking it to do bolder things.

  • Multi-variant rewrites. Our rewrite tool ships four tones in parallel (Add Numbers, Power Up, Match Job, Make Concise). Each variant runs through the same 17 guards independently. Variants that fail are dropped from the output. If all four fail, the user sees a hint asking for more specific facts instead of a fabricated rewrite.
  • The X-ray button. On the dashboard, every bullet has a recruiter X-ray panel. It shows you why a bullet reads as AI-shaped if it does, and quotes a guard-passed gold-standard rewrite next to the original. Both the diagnostic prompt and the gold-standard rewrite run through the guards. If the gold-standard fails, the X-ray shows the critique without the rewrite, because no rewrite is better than a bad rewrite.
  • Slash-merge. When you split a long bullet into two, both halves run through the guards individually. The split itself cannot introduce hallucinations.
  • The Polish All flow. Polish All rewrites every amber bullet in your resume in one batch. Every rewrite runs through 17 guards. The summary at the end shows you how many were rewritten, how many were kept as-is because the rewrite failed a guard, and how many need a new detail from you before they can be safely strengthened.

None of these features is possible without the substrate. Or rather, they are possible. Other tools ship them. They are just shipping unguarded.

What I would build next if I were them

If I were Teal, Rezi, or any other competitor, here is what I would do this quarter:

  1. Build the em-dash stripper. It is two hours of work. There is no excuse not to ship this.
  2. Build the verb-strength guard. One week of work for the basic version, two weeks for one that handles the edge cases.
  3. Hire someone whose job is to audit production output weekly and add a failure case to the guard library every time the model slips. This person is not an engineer. They are a recruiter or a hiring manager. The cost is a part-time contract. The reward is the entire moat.
  4. Publish the guard library on GitHub. Not all of it. The em-dash stripper. The basic verb checks. Make it the industry standard. Become the company that defines the category.

If anyone from those teams is reading this, copy this list. I would rather compete on which guard library is best than on which has guards at all.

Try it

The guards run on every bullet rewrite we produce. The fastest way to see them work is:

[Open the free Bullet Rewriter](/tools/resume-bullet-rewriter) (no signup, 4 modes).

Paste one weak bullet from your CV. Click rewrite. Try to find an em-dash in the output. Try to find a "leveraged". You will not.

Then paste the same bullet into the highest-rated competitor you can find and run the same check.

That comparison is the entire pitch. I do not need to argue this on benchmarks or pricing. The output speaks. The output is what reaches a hiring manager.

If you decide ApplyArc is the right tool for you, the resume tooling is part of an 18-tool job search suite at £19 per month, or £15 per month annual. You can start with the free tier (5 AI generations, no credit card). All 17 guards run on the free tier. We do not gate quality by plan.

Methodology and disclosures

The February 2026 competitor audit used the same input bullet across all five tools: "Worked on the data quality dashboard team during the platform migration." Each tool was asked to generate 10 rewrites (or as many as its free tier permitted, padded with paid tier generations). Em-dash count is unmodified character count of in raw output. "Leveraged family" is total occurrences of leveraged, spearheaded, or utilized (case-insensitive). Fabricated leadership is a manual review of whether the rewrite swapped the contribution verb to a leadership verb with no new metric.

I am the founder of ApplyArc. I have a financial interest in you choosing us. I have tried to surface every claim with a specific, replicable check so that interest is the smallest possible factor in your decision.

The line numbers cited in this post are from bulletRewriteGuards.js at commit 0f2b9806 on the develop branch as of 24 May 2026. The file is in our backend; the source is not public, but if any researcher wants to audit it under NDA, the contact is hello@applyarc.com.

#AI Resume Detection#Resume Tools#AI Tells#ChatGPT Resume#Engineering

George-Adrian

Founder & Engineer, ApplyArc

George-Adrian builds and ships ApplyArc end-to-end. He writes about the engineering behind the product, the guards that catch AI tells, the eval harness, and the rewrites that keep cost and latency down.

Stop losing track of applications

ApplyArc tracks everything automatically, for free.

Try Free Tracker

Related Articles