Common LaTeX Layout Issues and Fixes in the AI Job Search Framework
The AI Job Search framework prevents orphaned headings, page overflows, font mismatches, and ATS extraction errors by automating LaTeX compilation with lualatex and xelatex, injecting \needspace commands, and running verify_pdf.py to validate page counts and text layers.
The MadsLorentzen/ai-job-search repository provides a fully automated pipeline for generating job application documents, but LaTeX rendering can diverge significantly between source .tex files and the resulting PDF output. To ensure consistent, ATS-friendly results, the framework anticipates recurring LaTeX layout issues and applies concrete remedies through automated checks and source code modifications.
Orphaned Headings and Section Breaks
A common LaTeX problem occurs when a section heading lands at the bottom of a page while its content starts on the next page, creating visual orphans. The framework fixes this by pre-emptively reserving vertical space before critical headings.
In cv/main_example.tex, the template injects \needspace{<n>}{<heading>} to force a page break when insufficient space remains:
\needspace{3\baselineskip}
\section{Professional Experience}
This command ensures that if a heading cannot fit with at least three lines of following content, LaTeX breaks the page before the heading rather than after it.
CV Page Overflow Control
The default moderncv layout has no built-in enforcement for the two-page limit common in industry standards. Without intervention, bullet points and experience entries accumulate until the CV spills onto a third page.
The framework solves this through relevance-weighted CV cutting. The /apply workflow runs tools/verify_pdf.py, which parses the compiled PDF, counts pages, and automatically rewrites the LaTeX source to drop or shrink the lowest-scoring lines when the document exceeds two pages. This validation step ensures the final output strictly adheres to the two-page constraint regardless of input length.
Cover Letter Length Management
The custom cover.cls class is designed for a single-page cover letter, but long paragraphs can push content onto a second page due to fixed-height headers and generous margins.
The framework addresses this in cover_letters/cover.cls by strategically applying \enlargethispage{<len>} to add extra capacity when needed:
\enlargethispage{2\baselineskip}
When verify_pdf.py detects a two-page cover letter during the verification step, it automatically triggers space adjustments or content trimming to compress the letter back to a single page.
Font Mismatches and Missing Glyphs
Font handling represents a critical LaTeX layout issue, particularly when using fontawesome5 icons for contact information. On standard PDFLaTeX installations, OpenType icon glyphs may not embed properly, resulting in blank symbols in the final PDF.
The framework mandates specific Unicode-aware engines to resolve this:
- CV compilation uses lualatex (required for
moderncvwithfontawesome5) - Cover letter compilation uses xelatex (required for
fontspecand custom Lato/Raleway fonts)
The README specifies these prerequisites explicitly, ensuring proper Unicode handling for icon fonts and preventing glyph substitution failures across different TeX installations.
Missing Package Dependencies
Minimal TeX distributions such as TinyTeX or BasicTeX ship only core packages, causing compilation failures when moderncv, fontawesome5, or fontspec are missing.
The framework mitigates this through preventive documentation and CI validation. The README lists exact extra packages to install, while .github/workflows/ci.yml runs smoke-compilation tests to catch missing dependencies early in the development cycle. This ensures that environment setup issues surface before job application deadlines.
ATS Text Extraction Validation
PDF text layers can contain invisible control characters or render glyphs as images rather than searchable text, breaking keyword matching in Applicant Tracking Systems (ATS).
After compilation, tools/verify_pdf.py validates extractability using pdftotext (with pypdf as fallback):
from pathlib import Path
from pypdf import PdfReader
pdf = PdfReader(Path("output.pdf"))
assert len(pdf.pages) == 2 # CV must be 2 pages
text = "\n".join(page.extract_text() for page in pdf.pages)
assert "email@example.com" in text.lower()
This verification extracts the text layer, validates contact fields, and flags any non-extractable content before the application is submitted.
The Automated /apply Workflow
All LaTeX layout safeguards integrate into a single command flow that iteratively refines the output:
- Compile: Draft LaTeX processes through
lualatex(CV) orxelatex(cover letter) - Verify:
tools/verify_pdf.pyextracts page counts and text layers, detecting layout anomalies - Rewrite: If problems exist, the workflow automatically modifies source code (adding
\needspace, trimming low-score lines, inserting\enlargethispage) - Recompile: The PDF rebuilds until the CV is exactly 2 pages and the cover letter 1 page with clean text extraction
This loop ensures reliable output across different TeX installations while guaranteeing ATS compatibility.
Summary
- Orphaned headings are prevented using
\needspacecommands incv/main_example.texto keep headings with their content blocks - Page overflow is managed by
verify_pdf.py, which automatically trims low-relevance content to enforce strict two-page CV and one-page cover letter limits - Font issues are eliminated by compiling with
lualatex(CV) andxelatex(cover letter) rather than standard PDFLaTeX - Missing packages are caught early through CI smoke tests in
.github/workflows/ci.ymland explicit README documentation - ATS compatibility is verified by extracting text layers with
pypdfto ensure searchable content and proper glyph embedding
Frequently Asked Questions
Why does the framework use different LaTeX engines for the CV and cover letter?
The CV requires lualatex because the moderncv class with fontawesome5 icons needs Unicode-aware font handling that PDFLaTeX cannot provide. The cover letter uses xelatex because the custom cover.cls relies on fontspec to load system fonts like Lato and Raleway. Using the correct engine prevents blank glyphs and ensures consistent font rendering across operating systems.
How does the framework prevent the CV from exceeding two pages?
The tools/verify_pdf.py script parses the compiled PDF to count pages. If the CV exceeds two pages, the framework automatically rewrites the LaTeX source to remove or shrink the lowest-scoring experience bullets based on relevance weighting. This process repeats until the document fits the two-page constraint without manual editing.
What causes font icons to appear blank in the PDF, and how is it fixed?
Blank icons occur when the TeX engine cannot embed OpenType glyphs from fontawesome5. The framework fixes this by mandating lualatex for CV compilation, which properly handles Unicode icon fonts. Additionally, the README documents all required font packages to ensure they are installed before compilation begins.
How does verify_pdf.py ensure ATS compatibility?
The script extracts the PDF text layer using pdftotext or the pypdf library, then validates that contact information and key terms are searchable and not rendered as images. It asserts specific page counts (two for CV, one for cover letter) and verifies that extracted text contains expected content, flagging any non-extractable glyphs or invisible control characters that could break keyword matching.
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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →