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.
⚡ The short version
Tap to readCollapse
⚡ The short version
📋 Table of Contents
⚡ The short version
Tap to readCollapse
⚡ The short version
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):
| Tool | Em-dash rate | "Leveraged" / "Spearheaded" / "Utilized" | Fabricated leadership verbs |
|---|---|---|---|
| TealCompare → | 38% | 4 of 10 | 2 of 10 |
| ReziCompare → | 41% | 3 of 10 | 1 of 10 |
| Resume WordedCompare → | 33% | 5 of 10 | 3 of 10 |
| EnhancvCompare → | 47% | 4 of 10 | 2 of 10 |
| KickresumeCompare → | 29% | 6 of 10 | 1 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.
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 verbsDOWNGRADE_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:
paletteViolationGuardcatches "Managed X" being swapped to "Led X" or "Drove X" without new evidence.gerundPromotionGuardcatches "Built X" being wrapped as "Led the build of X" (the same lie in a noun phrase costume).doerToLeadershipGuardcatches 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:
| Pass | Guard | What it stops |
|---|---|---|
| 1c | meta-commentary | "Removed the leveraged wording" written into the bullet itself |
| 3 | padding | Rewrite added words without adding new information |
| 3b | over-length cap | Bullets above 32 words that wrap to 3+ lines on a standard template |
| 4b | body-fluff | Vague tails ("by changing how we handled X") |
| 4c | body-weak-verb | Hedge verbs in the second clause ("and backed workforce growth") |
| 4d | body-adverb | "Proactively", "seamlessly", "successfully" anywhere in the bullet |
| 4e | readability | Flesch-Kincaid density spike vs the original |
| 5b | palette violation | "Managed" upgraded to "Led" with no new evidence |
| 5c | gerund promotion | "Built X" upgraded to "Led the build of X" |
| 5d | origin fabrication | "Translated" upgraded to "Architected" (different authorship claim) |
| 5e | doer-to-leadership | Bare "Built X" to "Led X" swap |
| 6 | seniority fabrication | Junior bullets using exec verbs, or vice versa |
| 6b | variant integrity | Across 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 decideWhy nobody else does this
I cannot prove competitors do not do this. What I can say:
- 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.
- 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.
- Building the guard layer is expensive.
bulletRewriteGuards.jsis 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.
- 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.
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:
- Build the em-dash stripper. It is two hours of work. There is no excuse not to ship this.
- Build the verb-strength guard. One week of work for the basic version, two weeks for one that handles the edge cases.
- 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.
- 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.
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.
Related Articles
How to Make an AI Resume Sound Human (2026 Guide)
Recruiters reject AI-written resumes on sight. Here are the 7 words that give you away, how ATS systems flag ChatGPT output, and how to fix a robotic resume in 10 minutes.
Ghost Jobs Hit 40% Of Listings in 2026. Here's How to Spot Them in 60 Seconds.
Forbes reported in April 2026 that around 40% of US public job postings show ghost-job indicators. I built the 4-signal triage ApplyArc uses to score every saved job: posting age, named recruiter, presence on the company careers page, salary band. No AI in the loop. Free 60-second checklist inside.