# How Hiring Agent Converts PDF Resumes to Markdown: A Technical Deep Dive

> Discover how Hiring Agent converts PDF resumes to Markdown. Explore its two-step pipeline using PyMuPDF and a custom to_markdown function for efficient text extraction and formatting.

- Repository: [HackerRank/hiring-agent](https://github.com/interviewstreet/hiring-agent)
- Tags: deep-dive
- Published: 2026-07-17

---

**The Hiring Agent converts PDF résumés to Markdown using a two-step pipeline that first loads the document with PyMuPDF, then processes pages through a specialized `to_markdown` function that detects headers, extracts tables and images, and normalizes formatting into clean Markdown syntax.**

The interviewstreet/hiring-agent repository automates résumé parsing for recruitment workflows using a sophisticated document processing pipeline. Understanding how it converts PDF resumes to Markdown reveals the underlying architecture that enables accurate extraction of candidate information for downstream LLM processing.

## The Two-Step PDF to Markdown Pipeline

The conversion process implemented in the Hiring Agent follows a clear separation between document ingestion and content transformation. This architecture ensures reliable handling of complex PDF layouts while producing clean, structured Markdown suitable for automated parsing.

### Step 1: PDF Loading and Page Selection

The process begins in [`pdf.py`](https://github.com/interviewstreet/hiring-agent/blob/main/pdf.py) where the **`PDFHandler`** class orchestrates document access. The handler utilizes **PyMuPDF** (`pymupdf.open`) to load the PDF file and determine which pages require processing.

The `extract_text_from_pdf` method (lines 47-58) serves as the entry point. It accepts a file path, opens the document, and builds a list of page numbers to process. This selective approach allows the system to handle multi-page résumés efficiently while ignoring blank pages or irrelevant sections.

### Step 2: Markdown Conversion and Structure Detection

Once the document is loaded, the handler passes the PyMuPDF document object and page range to the **`to_markdown`** function defined in [`pymupdf_rag.py`](https://github.com/interviewstreet/hiring-agent/blob/main/pymupdf_rag.py) (lines 32-85). This function performs the heavy lifting of content extraction and formatting.

The conversion logic includes several sophisticated operations:

- **Header hierarchy detection** using the `IdentifyHeaders` class, which analyzes font sizes to distinguish between H1, H2, and H3 equivalent sections
- **Table extraction** and rendering into Markdown table syntax
- **Image and vector graphics** identification and processing
- **Column-by-column page traversal** that respects complex multi-column layouts common in résumés
- **Formatting preservation** including bullet lists, code blocks, bold, italic, and strikethrough styling
- **Hyperlink resolution** converting PDF annotations into proper Markdown link syntax
- **Artefact stripping** and whitespace normalization to produce clean output

The resulting Markdown string preserves the semantic structure of the original résumé while removing PDF-specific formatting debris, making it ideal for subsequent LLM parsing.

## Key Implementation Files and Functions

Three primary files constitute the PDF processing architecture:

- **[`pdf.py`](https://github.com/interviewstreet/hiring-agent/blob/main/pdf.py)** – Contains the `PDFHandler` class that orchestrates PDF opening and delegates to the markdown converter
- **[`pymupdf_rag.py`](https://github.com/interviewstreet/hiring-agent/blob/main/pymupdf_rag.py)** – Implements the `to_markdown` function and supporting classes like `IdentifyHeaders` and `write_text` that perform structure detection and content extraction
- **[`transform.py`](https://github.com/interviewstreet/hiring-agent/blob/main/transform.py)** – Handles post-processing of the Markdown into structured JSON resume objects after conversion is complete

## Practical Code Examples

You can interact with the PDF to Markdown pipeline at two levels of abstraction depending on your integration needs.

### High-Level PDFHandler Usage

For standard résumé processing, use the `PDFHandler` class which manages the entire pipeline:

```python
from pdf import PDFHandler

pdf_path = "candidate_resume.pdf"
handler = PDFHandler()

# Step 1 – extract raw Markdown from the PDF

markdown_resume = handler.extract_text_from_pdf(pdf_path)

print(markdown_resume[:500])   # show the first 500 characters

```

### Direct Low-Level Conversion

For custom page ranges or advanced configurations, access the `to_markdown` function directly:

```python
import pymupdf
from pymupdf_rag import to_markdown

doc = pymupdf.open("candidate_resume.pdf")

# Convert the whole document (pages are zero‑based)

md = to_markdown(doc, pages=range(doc.page_count))

print(md)   # full Markdown representation of the PDF

```

## Summary

- The Hiring Agent employs a two-stage pipeline separating document loading from content conversion to ensure reliable PDF resume processing.
- **PyMuPDF** serves as the foundation for PDF parsing, with the `PDFHandler` class in [`pdf.py`](https://github.com/interviewstreet/hiring-agent/blob/main/pdf.py) managing document access and page selection.
- The **`to_markdown`** function in [`pymupdf_rag.py`](https://github.com/interviewstreet/hiring-agent/blob/main/pymupdf_rag.py) performs sophisticated layout analysis including header detection via font sizing, table extraction, and formatting preservation.
- The resulting Markdown undergoes normalization to remove artefacts before being passed to LLM parsers for section-wise extraction of candidate data.

## Frequently Asked Questions

### What library does Hiring Agent use to parse PDF files?

The system uses **PyMuPDF** (imported as `pymupdf`) to open and read PDF documents. This library provides the low-level access to page content, font metadata, and document structure necessary for accurate text extraction and layout analysis.

### How does Hiring Agent detect headings and structure in PDF resumes?

The implementation uses an **`IdentifyHeaders`** class that analyzes font sizes across the document to establish a header hierarchy. By comparing text sizes against calculated thresholds, the system distinguishes between section headers, subsections, and body text, converting these into appropriate Markdown heading levels (H1-H3).

### Can the Markdown conversion handle tables and images from PDFs?

Yes. The `to_markdown` function in [`pymupdf_rag.py`](https://github.com/interviewstreet/hiring-agent/blob/main/pymupdf_rag.py) specifically extracts and renders tables into Markdown table syntax, while also processing images and vector graphics encountered during the column-by-column page traversal. This ensures that structured data in résumés remains accessible in the Markdown output.

### Where is the PDF to Markdown conversion logic located in the repository?

The primary conversion logic resides in **[`pymupdf_rag.py`](https://github.com/interviewstreet/hiring-agent/blob/main/pymupdf_rag.py)** (lines 32-85), which contains the `to_markdown` function and supporting utilities. The orchestration layer that manages PDF loading is in **[`pdf.py`](https://github.com/interviewstreet/hiring-agent/blob/main/pdf.py)** (lines 47-58), while post-processing into structured JSON occurs in [`transform.py`](https://github.com/interviewstreet/hiring-agent/blob/main/transform.py).