How Hiring Agent Extracts Text from PDF Resumes: A Complete Technical Guide

Hiring Agent extracts text from PDF resumes by converting each page into clean Markdown using PyMuPDF, then feeding that structured text to LLM-based parsers to generate a JSON representation of the resume.

The interviewstreet/hiring-agent repository provides a robust pipeline for parsing unstructured PDF resumes into structured data. At the heart of this system is a sophisticated text extraction process that leverages PyMuPDF for document conversion and large language models for semantic understanding. This article examines how the system extracts text from PDF resumes through its modular architecture, tracing the journey from binary PDF files to structured JSON objects.

The PDF Processing Architecture

The extraction workflow follows a three-stage pipeline: document ingestion, Markdown conversion, and LLM-based structured parsing. This architecture separates concerns between low-level document processing and high-level semantic extraction, enabling reliable handling of diverse resume formats.

Step 1: PDF Ingestion and Validation

The PDFHandler Entry Point

The primary interface for extracting text from PDF resumes resides in pdf.py, specifically within the PDFHandler class. The method extract_text_from_pdf serves as the main entry point, accepting a file path and returning a Markdown string representation of the document.

According to the source code in pdf.py (lines 47-62), this method first validates that the file exists on disk, then opens the document using PyMuPDF's pymupdf.open() function. It delegates the heavy lifting of format conversion to the to_markdown helper function, ensuring that the handler remains focused on orchestration rather than low-level text extraction.

Direct Markdown Conversion

For debugging or standalone usage, developers can interact directly with the lower-level conversion layer. The to_markdown function in pymupdf_rag.py accepts a pymupdf.Document object and returns a formatted Markdown string. This function processes the document page by page, preserving hierarchical structure through header detection and maintaining formatting for tables and emphasis.

Step 2: Intelligent Content Extraction

Header Detection via IdentifyHeaders

The to_markdown function implements sophisticated layout analysis through the IdentifyHeaders class. This component maps font sizes in the PDF to Markdown header levels (H1-H6), ensuring that section hierarchies in the original resume—such as "Experience" or "Education"—are preserved in the extracted text.

As implemented in pymupdf_rag.py (lines 30-86), the extraction routine walks through each page, collecting text blocks, tables, and images. It emits properly formatted Markdown including headings, lists, code blocks, bold/italic styling, and hyperlinks. Tables are rendered as Markdown tables, while images can be either embedded or saved to disk depending on configuration.

Step 3: LLM-Based Structured Parsing

Once the raw Markdown text is obtained, PDFHandler transitions from extraction to semantic parsing. The class invokes a series of section-specific methods such as extract_basics_section, extract_work_section, and similar private methods prefixed with _call_llm_for_section.

Each method sends a specialized prompt to the configured LLM (default model configuration defined in prompt.py), passing the relevant Markdown excerpt. The LLM returns a JSON fragment that the system transforms into strongly-typed Pydantic models (JSONResume, Basics, Work, etc.) defined in models.py. The transform.py module handles the conversion between raw LLM output and these final data structures.

Practical Implementation Examples

The following examples demonstrate how to extract text from PDF resumes using the Hiring Agent codebase.

Extracting raw Markdown text:

from pdf import PDFHandler

# Initialize the handler

handler = PDFHandler()

# Extract clean Markdown text from a PDF resume

markdown = handler.extract_text_from_pdf("alice_resume.pdf")
print(markdown[:500])  # Preview first 500 characters

Parsing into structured JSON:


# Convert the extracted text into a structured JSON resume

structured = handler.extract_json_from_pdf("alice_resume.pdf")
print(structured.json())  # JSON representation of the resume

Direct low-level access for debugging:

import pymupdf as fitz
from pymupdf_rag import to_markdown

# Open document directly with PyMuPDF

doc = fitz.open("alice_resume.pdf")

# Convert specific page range to Markdown

md = to_markdown(doc, pages=range(doc.page_count))
print(md[:400])

Core Components and File Responsibilities

Understanding the file structure helps when extending or debugging the text extraction pipeline:

  • pdf.py: Contains the PDFHandler class, the main entry point for PDF-to-text conversion and LLM orchestration. Implements extract_text_from_pdf and the section-specific extraction methods.

  • pymupdf_rag.py: Houses the to_markdown implementation that transforms PyMuPDF documents into clean Markdown. Includes the IdentifyHeaders class for layout analysis and handles tables, images, and formatting.

  • prompt.py: Defines the default LLM model configuration and API key handling used by PDFHandler for semantic parsing.

  • models.py: Contains Pydantic data models (JSONResume, Basics, Work, Education, etc.) that receive the parsed JSON from the LLM.

  • transform.py: Provides helper functions that convert raw JSON responses from the LLM into the typed model objects defined in models.py.

Summary

  • Hiring Agent extracts text from PDF resumes using a two-phase approach: first converting PDFs to Markdown with PyMuPDF, then parsing that Markdown with LLMs.
  • The PDFHandler class in pdf.py orchestrates the workflow, while to_markdown in pymupdf_rag.py handles the low-level document conversion.
  • Header detection preserves document structure by mapping PDF font sizes to Markdown heading levels.
  • The system supports tables and images, rendering them as Markdown tables and embedded files respectively.
  • Section-specific LLM calls transform the Markdown text into structured JSON using Pydantic models defined in models.py.

Frequently Asked Questions

What library does Hiring Agent use to extract text from PDF resumes?

Hiring Agent uses PyMuPDF (imported as pymupdf or fitz) as its core PDF processing library. The extract_text_from_pdf method in PDFHandler opens documents with pymupdf.open(), and the to_markdown function processes the document object to extract text while preserving formatting and layout information.

How does Hiring Agent handle tables and images when extracting text from PDF resumes?

The to_markdown function in pymupdf_rag.py specifically handles tables by rendering them as Markdown tables with proper column alignment. For images, the system can either embed them using data URIs or save them to disk depending on the configuration. This ensures that visual information in resumes is preserved as structured data or references rather than being lost during text extraction.

Can I extract text from PDF resumes without using the LLM parsing?

Yes. The PDFHandler.extract_text_from_pdf method returns the raw Markdown text without invoking any LLM calls. You can also use the low-level to_markdown function directly from pymupdf_rag.py by passing a pymupdf.Document object, which is useful for debugging or when you only need the text content without structured data extraction.

Where is the LLM model configuration defined in the Hiring Agent repository?

The default LLM model configuration and API key handling are defined in prompt.py. This file contains the settings used by PDFHandler when calling _call_llm_for_section methods to parse specific resume sections like work experience or education. The configuration determines which model processes the Markdown text extracted from the PDF.

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 →