# How to Compile and Inspect Final PDFs in AI Job Search: A Complete Guide

> Compile your AI Job Search PDFs using lualatex and xelatex. Inspect final documents and ensure ATS compliance with our complete guide and verification script.

- Repository: [Mads Lorentzen/ai-job-search](https://github.com/MadsLorentzen/ai-job-search)
- Tags: how-to-guide
- Published: 2026-08-30

---

**Compile AI Job Search PDFs using `lualatex` for CVs and `xelatex` for cover letters, then verify ATS compliance with [`tools/verify_pdf.py`](https://github.com/MadsLorentzen/ai-job-search/blob/main/tools/verify_pdf.py).**

The [MadsLorentzen/ai-job-search](https://github.com/MadsLorentzen/ai-job-search) framework automates LaTeX generation for job applications. After running the `/apply` command, you must compile the generated sources and inspect the final PDFs to ensure they are ATS-ready. This guide covers the exact steps to compile and inspect final PDFs based on the source code implementation.

## Step 1: Generate LaTeX Sources with `/apply`

The workflow begins with the **application command**. Running `/apply <job_url>` creates two LaTeX files:

- **CV**: `cv/main_<company>_<role>.tex`
- **Cover letter**: `cover_letters/cover_<company>_<role>.tex`

According to [`SETUP.md`](https://github.com/MadsLorentzen/ai-job-search/blob/main/SETUP.md) (lines 88-96), this step populates templates with your profile data and the parsed job description. The files are ready for compilation immediately after generation.

## Step 2: Compile the CV with `lualatex`

The CV template uses the **`moderncv`** document class. The source code specifies **LuaLaTeX** as the required compiler—`pdflatex` frequently fails on newer MiKTeX installations due to font handling differences.

From [`SETUP.md`](https://github.com/MadsLorentzen/ai-job-search/blob/main/SETUP.md) (lines 45-53), run:

```bash
cd cv
lualatex -interaction=nonstopmode -halt-on-error main_<company>_<role>.tex
cd ..

```

The `nonstopmode` and `halt-on-error` flags ensure the process exits cleanly on compilation failures, making this suitable for automation pipelines.

## Step 3: Compile the Cover Letter with `xelatex`

The cover letter template (`cover_letters/cover.cls`) requires **XeLaTeX** due to custom font dependencies. As documented in [`SETUP.md`](https://github.com/MadsLorentzen/ai-job-search/blob/main/SETUP.md) (lines 45-53):

```bash
cd cover_letters
xelatex -interaction=nonstopmode -halt-on-error cover_<company>_<role>.tex
cd ..

```

**Critical distinction**: The CV and cover letter use different compilers. Mixing these causes font substitution errors or compilation failures.

## Step 4: Verify ATS Compliance with [`verify_pdf.py`](https://github.com/MadsLorentzen/ai-job-search/blob/main/verify_pdf.py)

After compilation, inspect final PDFs using the built-in verification tool at [`tools/verify_pdf.py`](https://github.com/MadsLorentzen/ai-job-search/blob/main/tools/verify_pdf.py). This script performs **text-layer extraction** and validation checks.

### Extraction Engine

The `extract_text_layer()` function (lines 4-86 in [`tools/verify_pdf.py`](https://github.com/MadsLorentzen/ai-job-search/blob/main/tools/verify_pdf.py)) implements a fallback strategy:

1. **Primary**: `pypdf` — pure Python, no external dependencies
2. **Fallback**: Poppler's `pdftotext` — command-line utility for complex PDFs

### Validation Checks

The script verifies:

- **Page count** — ensures the document is not unexpectedly truncated
- **Character count** — flags near-empty PDFs (common LaTeX rendering failures)
- **Required keywords** — confirms sections like "Professional Experience" are present

Run the verification:

```bash
python3 tools/verify_pdf.py path/to/your_cv.pdf

```

### Interpreting Output

Successful verification produces:

```

Verified cv/main_example.pdf (extractor: pypdf, pages: 2)

```

Failures raise a `VerificationError` with specific details:

- Missing required text segments
- Insufficient character count
- Wrong page count

## Step 5: Debug Text Layer Extraction

To manually inspect the extracted content, invoke the extraction function directly:

```bash
python3 -c "from tools.verify_pdf import extract_text_layer; \
text, pages, src = extract_text_layer('path/to/your_cv.pdf'); \
print(f'Extractor: {src}\nPages: {pages}\n---\n{text[:500]}')"

```

This reveals the **actual text layer** that ATS systems parse—distinct from the visual PDF rendering. Use this when verification fails to identify encoding issues or missing content.

## Complete Workflow Example

```bash

# 1. Generate LaTeX sources

/apply https://jobindex.dk/job/1234567

# 2. Compile CV

cd cv
lualatex -interaction=nonstopmode -halt-on-error main_example.tex
cd ..

# 3. Compile cover letter

cd cover_letters
xelatex -interaction=nonstopmode -halt-on-error cover_example.tex
cd ..

# 4. Verify both PDFs

python3 tools/verify_pdf.py cv/main_example.pdf
python3 tools/verify_pdf.py cover_letters/cover_example.pdf

```

## Key Implementation Files

| File | Purpose |
|------|---------|
| [`tools/verify_pdf.py`](https://github.com/MadsLorentzen/ai-job-search/blob/main/tools/verify_pdf.py) | PDF text extraction and ATS validation logic |
| `cv/main_example.tex` | Stock CV template (LuaLaTeX / `moderncv`) |
| `cover_letters/cover.cls` | Cover letter class (XeLaTeX, custom fonts) |
| [`SETUP.md`](https://github.com/MadsLorentzen/ai-job-search/blob/main/SETUP.md) | Compilation workflow documentation |

## Summary

- **`/apply`** generates LaTeX sources in `cv/` and `cover_letters/` directories
- **CV compilation** requires `lualatex` due to `moderncv` font requirements
- **Cover letter compilation** requires `xelatex` for custom font handling in `cover.cls`
- **[`tools/verify_pdf.py`](https://github.com/MadsLorentzen/ai-job-search/blob/main/tools/verify_pdf.py)** validates PDFs using `pypdf` with `pdftotext` fallback
- Verification checks page count, character count, and required keyword presence

## Frequently Asked Questions

### Why does the CV require LuaLaTeX instead of pdfLaTeX?

The `moderncv` document class uses modern font handling that conflicts with pdfLaTeX on current MiKTeX distributions. The `ai-job-search` source code in [`SETUP.md`](https://github.com/MadsLorentzen/ai-job-search/blob/main/SETUP.md) explicitly recommends `lualatex` to avoid compilation failures related to font substitution and encoding.

### What happens if [`verify_pdf.py`](https://github.com/MadsLorentzen/ai-job-search/blob/main/verify_pdf.py) cannot extract text from my PDF?

The `extract_text_layer()` function in [`tools/verify_pdf.py`](https://github.com/MadsLorentzen/ai-job-search/blob/main/tools/verify_pdf.py) first attempts extraction with `pypdf`. If that returns empty or garbled text, it automatically falls back to Poppler's `pdftotext` command-line tool. Both extractors are attempted before raising a `VerificationError`.

### Can I automate the entire compile-and-inspect pipeline?

Yes. The `nonstopmode` and `halt-on-error` flags make both `lualatex` and `xelatex` suitable for scripting. Chain the commands and add `python3 tools/verify_pdf.py` calls to create a fully automated workflow that fails fast on compilation or validation errors.

### How do I fix a "missing required text" verification error?

Open the `.tex` source and verify that standard section names like "Professional Experience" are spelled exactly as expected by [`verify_pdf.py`](https://github.com/MadsLorentzen/ai-job-search/blob/main/verify_pdf.py). Re-compile after corrections. Alternatively, use the direct extraction debug command to see exactly which text was detected in the PDF layer.