# Using Jinja Templates for Section-Specific Resume Parsing in the Hiring-Agent Repository

> Discover how the hiring agent repository uses Jinja templates to parse resume sections like work experience education and skills for structured LLM prompts with TemplateManager and PromptBuilder.

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

---

**The hiring-agent repository uses Jinja templates to render discrete sections of a resume—such as work experience, education, and skills—into structured LLM prompts through a centralized `TemplateManager` and `PromptBuilder` architecture.**

The [interviewstreet/hiring-agent](https://github.com/interviewstreet/hiring-agent) open-source project implements a modular parsing pipeline where each resume component maps to a dedicated Jinja template file. This design decouples prompt engineering from data extraction, allowing maintainers to update section-specific formatting in `.jinja` files without altering the core Python logic that orchestrates resume evaluation.

## Resume Section-to-Template Mapping

The explicit contract between code and templates is defined in [`prompts/template_manager.py`](https://github.com/interviewstreet/hiring-agent/blob/main/prompts/template_manager.py) inside the `TemplateManager` class. A dictionary named `SECTION_TEMPLATES` (lines 17–25) maps logical section names to their corresponding Jinja filenames:

```python
SECTION_TEMPLATES: Dict[str, str] = {
    "basics": "basics.jinja",
    "work": "work.jinja",
    "education": "education.jinja",
    "skills": "skills.jinja",
    "projects": "projects.jinja",
    "awards": "awards.jinja",
    "system_message": "system_message.jinja",
    "github_project_selection": "github_project_selection.jinja",
    "resume_evaluation_criteria": "resume_evaluation_criteria.jinja",
    "resume_evaluation_system_message": "resume_evaluation_system_message.jinja",
}

```

This registry enables the system to dynamically locate the correct template for any supported resume section or evaluation context.

## Template Environment and Loading Strategy

`TemplateManager` initializes a Jinja `Environment` configured with a `FileSystemLoader` pointing to the `prompts/templates` directory (lines 28–31). The `get_template(section: str)` method (lines 36–40) validates the requested section against `SECTION_TEMPLATES`, then returns the compiled `Template` object:

```python
def get_template(self, section: str) -> Template:
    template_name = self.SECTION_TEMPLATES.get(section)
    if not template_name:
        raise ValueError(f"No template configured for section: {section}")
    return self.env.get_template(template_name)

```

By centralizing template retrieval, the architecture ensures that missing or unsupported sections trigger explicit errors rather than silent failures.

## Rendering Section-Specific Prompts

Actual prompt construction happens in [`prompt.py`](https://github.com/interviewstreet/hiring-agent/blob/main/prompt.py) within the `PromptBuilder` class. The `build_section_prompt` method (lines 44–47) accepts a section identifier and a dictionary of structured data, retrieves the appropriate template via `TemplateManager`, and renders it:

```python
def build_section_prompt(self, section: str, data: Dict[str, Any]) -> str:
    """Render a prompt for a specific resume section using its Jinja template."""
    template = self.template_manager.get_template(section)
    return template.render(**data)

```

This injection pattern allows raw resume fields—such as company names, degree titles, or skill lists—to populate predefined Jinja placeholders, producing consistent, LLM-ready text blocks.

## Full Resume Assembly Pipeline

For end-to-end evaluation, `PromptBuilder` aggregates individual section prompts into a cohesive document. The `build_resume_prompt` method (lines 49–53) iterates over a fixed sequence of core resume sections, renders each independently, and concatenates the results:

```python
def build_resume_prompt(self, resume_data: Dict[str, Any]) -> str:
    """Combine all section prompts into a single resume-level prompt."""
    sections = ["basics", "work", "education", "skills", "projects", "awards"]
    prompts = [self.build_section_prompt(sec, resume_data.get(sec, {})) for sec in sections]
    return "\n\n".join(prompts)

```

This approach preserves logical separation between resume components while presenting the language model with the complete candidate profile in a single context window.

## Practical Implementation Examples

To render a specific employment history section:

```python
from prompt import PromptBuilder

builder = PromptBuilder()
work_context = {
    "company": "Acme Corp",
    "position": "Senior Platform Engineer",
    "start_date": "2021-03",
    "end_date": "Present",
    "highlights": [
        "Architected microservices serving 1M+ daily requests",
        "Reduced deployment time by 40% via GitOps automation"
    ]
}

work_prompt = builder.build_section_prompt("work", work_context)
print(work_prompt)

```

To generate a comprehensive evaluation prompt from structured JSON:

```python
candidate_profile = {
    "basics": {"name": "Jane Doe", "email": "jane@example.com"},
    "work": [{"company": "TechCorp", "position": "Developer", "summary": "API development"}],
    "education": [{"institution": "State University", "area": "Computer Science"}],
    "skills": {"languages": ["Python", "Rust"], "frameworks": ["Django", "Axum"]},
    "projects": [{"name": "DataCLI", "description": "Open-source ETL utility"}],
    "awards": [{"title": "Hackathon Winner", "year": "2023"}]
}

builder = PromptBuilder()
evaluation_prompt = builder.build_resume_prompt(candidate_profile)

# evaluation_prompt now contains concatenated sections ready for LLM inference

```

## Summary

- **[`prompts/template_manager.py`](https://github.com/interviewstreet/hiring-agent/blob/main/prompts/template_manager.py)** defines the authoritative mapping of resume sections to Jinja templates via the `SECTION_TEMPLATES` dictionary (lines 17–25).
- The `TemplateManager` class establishes a reusable Jinja `Environment` with `FileSystemLoader` (lines 28–31) and exposes `get_template` for validated template retrieval (lines 36–40).
- **[`prompt.py`](https://github.com/interviewstreet/hiring-agent/blob/main/prompt.py)** implements `PromptBuilder`, which leverages `build_section_prompt` (lines 44–47) to inject data into section-specific templates and `build_resume_prompt` (lines 49–53) to aggregate outputs.
- This architecture supports ten distinct template types, spanning core resume sections (basics, work, education, skills, projects, awards) and evaluation-specific contexts (system messages, GitHub project selection, evaluation criteria).

## Frequently Asked Questions

### What types of resume sections are parsed using Jinja templates?

The system parses six primary candidate-facing sections—**basics**, **work**, **education**, **skills**, **projects**, and **awards**—plus four evaluation-specific templates including `system_message`, `github_project_selection`, `resume_evaluation_criteria`, and `resume_evaluation_system_message`. All mappings reside in the `SECTION_TEMPLATES` dictionary within [`template_manager.py`](https://github.com/interviewstreet/hiring-agent/blob/main/template_manager.py).

### How does the system handle sections with missing data?

When assembling a full resume prompt, `build_resume_prompt` passes an empty dictionary `{}` to `build_section_prompt` for any missing section keys. The underlying Jinja templates contain conditional logic (e.g., `{% if highlights %}...{% endif %}`) to gracefully skip optional fields, ensuring the final prompt remains clean even with incomplete candidate data.

### Can new resume sections be added without modifying the core parsing logic?

Yes. To add a section, create a new `.jinja` file in `prompts/templates` and append the section-to-filename mapping to `TemplateManager.SECTION_TEMPLATES`. The `PromptBuilder` automatically recognizes the new key during the next execution; no changes are required in [`prompt.py`](https://github.com/interviewstreet/hiring-agent/blob/main/prompt.py) or other downstream modules.

### Where does the TemplateManager look for Jinja template files?

The `TemplateManager` computes the template directory path dynamically using `os.path.dirname(__file__)` joined with `"templates"`, resolving to `prompts/templates` relative to the [`template_manager.py`](https://github.com/interviewstreet/hiring-agent/blob/main/template_manager.py) module location. This relative path strategy ensures portability across local development, containerized deployments, and CI environments.