# How AI-Job-Search Ensures PDF Quality Verification in the Apply Process

> The ai-job-search framework ensures PDF quality by verifying file existence, page count, text extractability, and content before submission for ATS compatibility.

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

---

**The ai-job-search framework validates every generated PDF before submission using the [`tools/verify_pdf.py`](https://github.com/MadsLorentzen/ai-job-search/blob/main/tools/verify_pdf.py) utility, which performs file existence, page count, text extractability, and required content checks to guarantee ATS compatibility.**

The ai-job-search framework automates the creation of tailored résumés and cover letters, but submitting a malformed or unscannable document can derail an application. To prevent this, the framework integrates a rigorous **PDF quality verification** step into the apply pipeline. This verification, implemented in [`tools/verify_pdf.py`](https://github.com/MadsLorentzen/ai-job-search/blob/main/tools/verify_pdf.py), runs a series of structural and content checks using external PDF tools before any document reaches a job portal.

## The PDF Quality Verification Pipeline

The verification process is orchestrated by the `verify_pdf` function in [`tools/verify_pdf.py`](https://github.com/MadsLorentzen/ai-job-search/blob/main/tools/verify_pdf.py). This utility performs four distinct validation layers to guarantee that every generated document meets professional standards and ATS readability requirements.

### File Existence Validation

Before any content analysis begins, the framework confirms the PDF file exists on disk. The `verify_pdf` function uses `Path(pdf_path).is_file()` to verify presence. If the file is missing, the function immediately raises a `VerificationError`, halting the apply process before any further steps are attempted.

### Page Count Verification

Recruiters often enforce strict page limits for résumés. When the caller provides an expected page count via the `--pages` argument, the tool executes the external `pdfinfo` command through the `run_tool` helper. The `parse_page_count` function then extracts the "Pages" field from the output using the regex pattern `^Pages:\s+(\d+)$`. If the actual page count deviates from the expected value, the framework raises a `VerificationError` and aborts the submission.

### Text Layer Extraction

For a PDF to be ATS-readable, it must contain an extractable text layer rather than just scanned images. The verification script calls `pdftotext -layout` to extract the document's text content, then normalizes whitespace using `normalize_text`. The resulting string length is compared against a minimum character threshold specified by `--min-chars` (defaulting to 1). Documents failing this check are rejected as non-readable.

### Required Content Verification

Beyond structural integrity, the framework can validate that specific phrases or sections appear in the document. Using the `--contains` option, callers specify required text strings that must be present in the PDF. Each phrase is normalized and searched within the extracted text layer. If any required phrase is missing, the `VerificationError` is raised, ensuring critical sections like "Professional Experience" or "Education" are never accidentally omitted.

## Integration with the Apply Workflow

The verification step is not optional—it is embedded directly into the apply command workflow. Before uploading to any job portal, the framework invokes `verify_pdf` with parameters appropriate for the specific application. This integration ensures that every résumé or cover letter passes quality gates automatically, preventing submissions of corrupted, unscannable, or incomplete documents.

## Error Handling and CLI Usage

All verification failures raise a `VerificationError`, which the CLI layer catches and handles gracefully. The error message is printed to `stderr`, and the process returns a non-zero exit code. This design prevents the subsequent apply step from proceeding when validation fails, maintaining the integrity of the job application pipeline. Users can also invoke the verifier manually via command line:

```bash
python -m tools.verify_pdf output/resume.pdf --pages 2 --min-chars 500 \
    --contains "Professional Experience" --contains "Education"

```

## Programmatic Verification Example

Developers integrating with the framework can invoke verification programmatically to intercept bad PDFs before they reach the apply stage:

```python
from tools.verify_pdf import verify_pdf, VerificationError

pdf_path = "output/resume.pdf"
try:
    verify_pdf(
        pdf_path,
        expected_pages=2,          # Must be exactly 2 pages

        min_chars=500,             # At least 500 characters of selectable text

        required_text=("Professional Experience", "Education")
    )
    print("PDF passes all quality checks – ready to apply.")
except VerificationError as err:
    print(f"PDF validation failed: {err}")

```

## Summary

- The ai-job-search framework validates every PDF through [`tools/verify_pdf.py`](https://github.com/MadsLorentzen/ai-job-search/blob/main/tools/verify_pdf.py) before submission.
- **File existence** checks prevent processing of missing documents.
- **Page count verification** uses `pdfinfo` to enforce length requirements.
- **Text extraction** via `pdftotext` ensures ATS compatibility by verifying selectable text exceeds `--min-chars`.
- **Content validation** confirms required phrases are present using `--contains`.
- All failures raise `VerificationError` with non-zero exit codes to halt the apply process.

## Frequently Asked Questions

### What happens if the PDF file does not exist during verification?

The `verify_pdf` function checks `Path(pdf_path).is_file()` immediately upon invocation. If the file is missing, it raises a `VerificationError` before attempting any content analysis, ensuring the apply process stops early with a clear error message.

### How does the framework verify that a PDF is not just a scanned image?

The tool runs `pdftotext -layout` to extract text content and measures the resulting string length against the `--min-chars` threshold. If the extraction yields fewer characters than specified (defaulting to 1), the document is flagged as lacking an extractable text layer, making it unreadable by ATS systems.

### Can I require specific sections to appear in the generated PDF?

Yes. Pass the `--contains` argument when calling `verify_pdf` to specify mandatory phrases. The tool normalizes both the extracted text and the search phrases, then verifies each required string is present. Missing content triggers a `VerificationError`, preventing submission of incomplete documents.

### Where are the tests for the PDF verification logic?

The verification behavior is validated by unit tests in [`tests/test_verify_pdf.py`](https://github.com/MadsLorentzen/ai-job-search/blob/main/tests/test_verify_pdf.py). These tests ensure the `verify_pdf` function correctly handles file existence, page count parsing, text extraction failures, and required content matching across various edge cases.