# JSON Resume Schema in Hiring Agent: Standardized Data Models Explained

> Learn how the Hiring Agent project uses the official JSON Resume schema to standardize candidate data. Explore type-safe Pydantic models for robust résumé validation and structuring.

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

---

**The Hiring Agent project adopts the official JSON Resume specification as its canonical data model, implementing type-safe Pydantic models in [`models.py`](https://github.com/interviewstreet/hiring-agent/blob/main/models.py) to validate and structure candidate résumés.**

The `interviewstreet/hiring-agent` repository automates candidate evaluation through LLM extraction and GitHub profile enrichment. To ensure consistent data handling across pipelines, the project leverages the **JSON Resume schema** as its standardized interchange format, encoding the specification via robust Python data models that guarantee interoperability with external tools.

## Schema Implementation in models.py

The complete **JSON Resume schema** definition resides in **[`models.py`](https://github.com/interviewstreet/hiring-agent/blob/main/models.py)**, where the `JSONResume` class acts as the root container (defined around lines 200-216). This class aggregates all resume sections as optional Pydantic fields, mirroring the official JSON Resume specification exactly.

### Core Data Models

Each resume section maps to a dedicated Pydantic model with strict type annotations:

| Section | Model | Key Fields |
|---------|-------|------------|
| **Basics** | `Basics` | `name`, `email`, `phone`, `url`, `summary`, `location`, `profiles` |
| **Work Experience** | `Work` | `name`, `position`, `url`, `startDate`, `endDate`, `summary`, `highlights` |
| **Education** | `Education` | `institution`, `url`, `area`, `studyType`, `startDate`, `endDate`, `score`, `courses` |
| **Skills** | `Skill` | `name`, `level`, `keywords` |
| **Projects** | `Project` | `name`, `startDate`, `endDate`, `description`, `highlights`, `url`, `technologies`, `skills` |
| **Awards** | `Award` | `title`, `date`, `awarder`, `summary` |
| **Certificates** | `Certificate` | `name`, `date`, `issuer`, `url` |
| **Publications** | `Publication` | `name`, `publisher`, `releaseDate`, `url`, `summary` |
| **Languages** | `Language` | `language`, `fluency` |
| **Interests** | `Interest` | `name`, `keywords` |
| **References** | `Reference` | `name`, `reference` |
| **Volunteer Work** | `Volunteer` | `organization`, `position`, `url`, `startDate`, `endDate`, `summary`, `highlights` |

All fields within these models are optional, allowing the schema to accommodate partial résumés while maintaining strict type safety for any provided data.

## Creating and Validating Resume Data

### Instantiation with Pydantic Models

You can construct resume objects programmatically using the model classes defined in **[`models.py`](https://github.com/interviewstreet/hiring-agent/blob/main/models.py)**:

```python
from models import JSONResume, Basics, Location, Profile, Work, Education, Skill, Project

resume = JSONResume(
    basics=Basics(
        name="Alice Doe",
        email="alice@example.com",
        location=Location(city="San Francisco", region="CA", countryCode="US"),
        profiles=[
            Profile(network="GitHub", username="alice", url="https://github.com/alice")
        ],
    ),
    work=[
        Work(
            name="Acme Corp",
            position="Software Engineer",
            startDate="2020-01",
            endDate="Present",
            summary="Built scalable backend services.",
        )
    ],
    education=[
        Education(
            institution="University of Example",
            studyType="Bachelor",
            area="Computer Science",
            startDate="2016-09",
            endDate="2020-06",
            score="3.9",
        )
    ],
    skills=[
        Skill(name="Programming Languages", keywords=["Python", "Go", "Rust"])
    ],
    projects=[
        Project(
            name="OpenAI-Wrapper",
            description="A Python wrapper for OpenAI APIs.",
            url="https://github.com/alice/openai-wrapper",
            technologies=["Python", "FastAPI"],
        )
    ],
)

```

### JSON Serialization

Convert validated objects to standard JSON format using Pydantic's built-in methods:

```python
import json

json_output = resume.json(indent=2)

```

This produces output conforming to the JSON Resume schema, ready for storage or API transmission.

### Schema Validation and Parsing

When ingesting external data, use **`parse_obj()`** to validate against the JSON Resume schema:

```python
from models import JSONResume

with open("candidate_resume.json") as f:
    data = json.load(f)

validated_resume = JSONResume.parse_obj(data)

```

If any field violates the expected type constraints, Pydantic raises a validation error immediately, preventing downstream processing of malformed data.

## Integration with LLM Pipelines

The project enforces **JSON Resume schema** compliance during LLM extraction through two critical components:

- **[`transform.py`](https://github.com/interviewstreet/hiring-agent/blob/main/transform.py)**: Normalizes raw LLM outputs into the strict JSON Resume structure defined in [`models.py`](https://github.com/interviewstreet/hiring-agent/blob/main/models.py)
- **[`prompt.py`](https://github.com/interviewstreet/hiring-agent/blob/main/prompt.py)** and **`prompts/templates/*.jinja`**: Jinja templates instruct the LLM to generate output conforming to the exact property names and types expected by the schema

This ensures that unstructured résumé text converts reliably into the standardized format before evaluation and enrichment.

## Summary

- The **JSON Resume schema** provides the canonical data model for all candidate information in the Hiring Agent project
- **[`models.py`](https://github.com/interviewstreet/hiring-agent/blob/main/models.py)** implements the complete specification using Pydantic classes (`JSONResume`, `Basics`, `Work`, `Education`, etc.)
- **Type-safe validation** occurs via `parse_obj()`, preventing malformed data from entering the pipeline
- **LLM outputs** are normalized through [`transform.py`](https://github.com/interviewstreet/hiring-agent/blob/main/transform.py) and schema-specific prompts to guarantee compliance
- All schema fields are optional, accommodating partial résumés while maintaining strict validation for provided data

## Frequently Asked Questions

### What specific JSON Resume version does the Hiring Agent implement?

The Hiring Agent implements the standard JSON Resume specification as defined at jsonresume.org. The Pydantic models in [`models.py`](https://github.com/interviewstreet/hiring-agent/blob/main/models.py) reflect the current stable schema, covering all standard sections including basics, work, education, skills, projects, awards, and certificates.

### How does the code handle incomplete résumé data?

All fields in the `JSONResume` model and its sub-models are optional, allowing partial résumés to validate successfully. Pydantic only enforces type constraints on fields that are actually present, so missing sections simply result in null values or empty lists in the JSON output without causing validation failures.

### Where does the conversion from LLM output to JSON Resume occur?

The **[`transform.py`](https://github.com/interviewstreet/hiring-agent/blob/main/transform.py)** module handles normalization of raw LLM outputs into the JSON Resume structure. Additionally, **[`prompt.py`](https://github.com/interviewstreet/hiring-agent/blob/main/prompt.py)** and the Jinja templates in `prompts/templates/` prime the LLM to emit data matching the expected schema property names and types directly, reducing the transformation burden.

### Can I extend the schema with custom fields?

While the base models strictly follow the official JSON Resume specification, Pydantic supports model inheritance. You can extend the existing classes in [`models.py`](https://github.com/interviewstreet/hiring-agent/blob/main/models.py) to include additional custom fields, though this may break compatibility with standard JSON Resume consumers unless they ignore unknown properties.