Limitations of the ATS Checking Feature in AI-Job-Search

The ATS checking feature in the AI-Job-Search repository relies on external PDF tools and assumes single-column layouts, making it unable to handle complex designs, missing utilities, or automatic keyword optimization.

The MadsLorentzen/ai-job-search repository automates CV generation with built-in applicant-tracking system (ATS) validation. While this feature helps ensure your résumé parses correctly, it carries specific constraints that prevent comprehensive coverage of modern CV formats. Understanding these ATS checking feature limitations helps you avoid false negatives and manual rework when preparing job applications.

Seven Critical Limitations of the ATS Checker

Dependency on External PDF Tools (pdftotext)

The validation step requires pdftotext from the Poppler utilities to extract the PDF's text layer. As documented in CLAUDE.md, if this tool is not installed on the host machine, the ATS verification is skipped entirely with only a warning message.

import subprocess
import pathlib

pdf_path = pathlib.Path("cv/main_company.tex").with_suffix(".pdf")

# Extract the text layer

result = subprocess.run(
    ["pdftotext", "-layout", str(pdf_path), "-"],
    capture_output=True,
    text=True,
)
extracted = result.stdout

This dependency means the ATS checking feature limitations include complete failure on environments lacking Poppler, potentially allowing unparsable PDFs to pass through undetected.

Single-Column Layout Assumptions

The checker expects a single-column, standard modern CV template. According to the source documentation in CLAUDE.md, "reading order of the extracted text matches the visual order (single-column stock template is safe; multi-column custom templates are where this breaks)."

Multi-column or heavily customized layouts can scramble the reading order during text extraction, causing the checker to miss content or report false positives. This constraint limits the feature to the repository's default two-page template.

Icon-Based Contact Information Risks

While the checker tolerates FontAwesome icons (envelope or mobile glyphs), contact details represented only by icons or hyperlinks become invisible to the ATS. The validation looks for literal text strings:

assert "@" in extracted and any(c.isdigit() for c in extracted), "Contact details missing"

As noted in CLAUDE.md, "email and phone appear as literal text in the extraction... a contact detail carried only by an icon is invisible to ATS." This creates a blind spot where visually complete CVs fail ATS parsing.

Manual Keyword Coverage Only

The ATS check verifies that exact posting keywords appear in the PDF text layer, but it does not automatically suggest missing keywords or rewrite bullets. Users must manually add keywords the profile genuinely supports to experience bullets, leaving genuine gaps visible rather than stuffing the document.

This limitation means the tool performs static validation rather than dynamic optimization. The tools/lint_skills.py file provides skill-linting that feeds into keyword coverage, but it requires manual intervention to update the LaTeX source.

Font Encoding and Character Handling

The extraction process may produce (cid:*) placeholders or replacement characters (``) when the PDF uses uncommon fonts or encodings. While the check flags these issues with assertions like assert "(cid:" not in extracted, it cannot automatically fix them.

PDFs embedding non-standard fonts or custom icons can lead to unreadable text for ATS parsers, and the checker only identifies the problem without resolving encoding issues.

LaTeX Engine Lock-In

The pipeline compiles CVs with lualatex (or xelatex for cover letters) as specified in CLAUDE.md: "CV compiled with lualatex... Cover letter compiled with xelatex." If users switch to a different engine or non-LaTeX résumé generator, the ATS verification may no longer apply correctly.

This engine specificity creates a hard dependency on the LaTeX toolchain, limiting the feature's utility for users preferring Markdown-based or word-processor workflows.

No Automated Re-Validation Workflow

After fixing a detected problem (such as adding missing contact text), users must manually re-compile and re-run the ATS check. The system does not auto-re-trigger verification upon file changes. As implied by the workflow description in CLAUDE.md, each change requires users to "run the tests" and "iterate until all pass," creating a risk that users overlook re-checking after edits.

How the ATS Check Works Under the Hood

The validation occurs in the final pipeline stage, extracting the PDF text layer and performing basic sanity checks:


# Basic sanity checks

assert "(cid:" not in extracted, "Found unreadable characters"
assert "@" in extracted and any(c.isdigit() for c in extracted), "Contact details missing"

The LaTeX template ensures contact details remain visible as plain text:

% LaTeX snippet that ensures contact details are present as plain text
\email{john.doe@example.com}
\mobile{+1 555-123-4567}
% Icons are allowed, but the plain text must also be present

Key files involved in this process include:

  • cv/ - Contains the LaTeX templates that generate the ATS-compatible two-page modern CV
  • CLAUDE.md - Documents the detailed verification checklist and ATS constraints
  • tools/lint_skills.py - Supports the manual keyword coverage step

Summary

  • External dependency: The pdftotext tool must be installed; otherwise, checks are silently skipped
  • Layout constraints: Only single-column templates parse reliably; multi-column designs break reading order
  • Text visibility: Contact information must appear as literal text, not just icons
  • Manual process: Keyword matching requires manual updates; no automatic rewrite or synonym suggestions
  • Encoding issues: Can detect (cid:*) markers but cannot fix font encoding problems automatically
  • Toolchain lock-in: Hardcoded for lualatex/xelatex compilation; other generators bypass checks
  • Manual iteration: Users must manually re-trigger validation after each edit; no continuous checking

Frequently Asked Questions

Can I use the ATS checker without installing Poppler utilities?

No, the check requires pdftotext from Poppler utilities. If the binary is missing, the verification step is skipped with a warning, potentially allowing unparsable PDFs to proceed unchecked. Install Poppler to ensure full validation coverage.

Why does my multi-column CV fail ATS validation even though it looks correct?

The extractor assumes a single-column reading order. Multi-column layouts often extract text in the wrong sequence (reading down column one, then column two, or interleaving lines incorrectly). Stick to the stock single-column template in cv/ to ensure accurate text extraction.

Does the tool automatically add missing keywords from the job posting?

No, the tool only verifies that keywords you have manually added appear in the text layer. It flags when exact terms are missing but does not suggest synonyms or rewrite your bullets. You must manually add supported keywords to your experience bullets.

How do I fix (cid:*) markers in my generated PDF?

These markers indicate font encoding issues where the PDF embeds non-standard fonts. The checker identifies these as errors but cannot repair them automatically. Switch to standard fonts supported by the LaTeX template (as defined in cv/) and recompile with lualatex to resolve the encoding.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →