Skip to main content

LLM-powered resume analysis, extraction, and scoring

Project description

Hyre
Hire on evidence, not vibes.
Reads a resume, extracts what matters, and shows you the full picture.

Website Python License: MIT

Our goal: take what HackerRank's Hiring Agent started and build on top of it. Better CLI, better output, cleaner code. Everything stays open source.

Install it with pip install -e . and the hyre command is available anywhere in your terminal. Or use the one-liner above.

Hyre turns a resume PDF into Markdown, runs it through LLM pipelines for layout analysis, data extraction, and scoring, then shows the results in a rich terminal UI.

Commands

hyre analyze <resume.pdf>     # Analyze resume layout
hyre extract <resume.pdf>     # Extract structured data (JSON Resume)
hyre evaluate <resume.pdf>    # Score resume across 4 categories

analyze (layout analysis)

┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃             Layout Analysis                     ┃
┃  Layout:    Two Column                          ┃
┃  Method:    Column boundary detection           ┃
┃  Confidence: high                               ┃
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛

Section Order
├─ Header
├─ Summary
├─ Experience
├─ Education
├─ Skills
└─ Projects

Subsections with Columns
┌──────────────┬─────────┬────────────────┬──────────┐
│ Subsection   │ Columns │ Items          │ Evidence │
├──────────────┼─────────┼────────────────┼──────────┤
│ Skills       │    2    │ Python, Go,... │ Sidebar  │
└──────────────┴─────────┴────────────────┴──────────┘

extract (structured data)

╭────────────────────────────────╮
│  Jane Doe                      │
│  fauzan@example.com            │
│  github.com/fauzan             │
╰────────────────────────────────╯

Work Experience (3)
├─ Senior Engineer @ Acme Corp    2021-03 – present
│  └─ Led team of 5, built microservice infra
├─ Software Engineer @ Beta Inc   2018-06 – 2021-02
│  └─ Built REST APIs, reduced latency 40%
└─ Junior Dev @ Gamma LLC         2016-01 – 2018-05
   └─ Maintained legacy app

Skills (4 categories)
┌──────────────┬──────────────────────────┐
│ Category     │ Skills                   │
├──────────────┼──────────────────────────┤
│ Languages    │ Python, TypeScript, Go   │
│ Frameworks   │ React, FastAPI, Next.js  │
│ Tools        │ Docker, Kubernetes       │
│ Databases    │ Postgres, Redis          │
└──────────────┴──────────────────────────┘

Education (1)
┌──────────────┬────────┬───────┬──────────────┬───────┐
│ Institution  │ Degree │ Field │ Dates        │ Score │
├──────────────┼────────┼───────┼──────────────┼───────┤
│ MIT          │ BSc    │ CS    │ 2012 – 2016  │ 3.8   │
└──────────────┴────────┴───────┴──────────────┴───────┘

evaluate (scoring)

╭──────────────────────────────────────╮
│  Resume Evaluation: Fauzan           │
╰──────────────────────────────────────╯

Category Scores
┌──────────────────┬─────────┬──────────────────────┬──────────────────┐
│ Category         │  Score  │ Bar                  │ Evidence         │
├──────────────────┼─────────┼──────────────────────┼──────────────────┤
│ Open Source      │  18/35  │ █████░░░░░░ 51%      │ 2 minor PRs      │
│ Self Projects    │  24/30  │ ████████░░ 80%       │ Strong portfolio │
│ Production       │  15/25  │ █████░░░░░░ 60%      │ 3 yrs exp        │
│ Technical Skills │   8/10  │ ██████████ 80%       │ Broad stack      │
├──────────────────┼─────────┼──────────────────────┼──────────────────┤
│ Total            │  65/100 │                      │                  │
│ Bonus: +5  Deductions: -2 │                      │ Final: 68/120    │
└──────────────────┴─────────┴──────────────────────┴──────────────────┘

╭─── Bonus Points (+5) ──────────────────────────────╮
│ Notable volunteer work, blog, GSoC participation   │
╰────────────────────────────────────────────────────╯

╭─── Deductions (-2) ────────────────────────────────╮
│ Missing GitHub links for 1 project                 │
╰────────────────────────────────────────────────────╯

╭─── Key Strengths ──────────────────────────────────╮
│ • Strong full-stack engineering experience         │
│ • Complex personal projects with real-world impact │
│ • Broad technical skills across the stack          │
╰────────────────────────────────────────────────────╯

╭─── Areas for Improvement ──────────────────────────╮
│ • Limited open source contributions                │
│ • Consider enhancing technical communication       │
╰────────────────────────────────────────────────────╯

How it works

PDF → Markdown → LLM → Structured Data → Rich TUI
│                  │            │
│ pymupdf4llm     │ Jinja      │ Typer + Rich
│                 │ templates  │

1. PDF → Text

PDFParser uses pymupdf4llm to convert PDF pages to clean Markdown. Headings, links, and tables all survive the round trip.

2. Text → Structured Data

The core.Hyre orchestrator sends the Markdown to an LLM with Jinja2 system prompts from core/prompts/. Each command (analyze, extract, evaluate) uses a different prompt template.

3. Rich TUI Output

Results render with rich: tables, trees, panels, color-coded score bars, and progress spinners while the LLM works.

Quick start

One-liner (Linux / macOS)

curl -sSL https://raw.githubusercontent.com/grandimam/hyre/main/install.sh | bash

Or if you prefer wget:

wget -qO- https://raw.githubusercontent.com/grandimam/hyre/main/install.sh | bash

This installs to ~/.hyre, creates a venv, and symlinks the hyre command to ~/.local/bin/hyre.

Prerequisites

Setup

git clone <your-repo-url> && cd hyre
python -m venv .venv && source .venv/bin/activate
pip install -e .

Configure

cp .env.example .env   # then edit .env with your OpenRouter API key

Run on the sample resume

hyre analyze examples/java-engineer.pdf
hyre extract examples/java-engineer.pdf
hyre evaluate examples/java-engineer.pdf

Configuration

Variable Default What it does
OPENROUTER_API_KEY required OpenRouter API key
MODEL_NAME openrouter/openai/gpt-3.5-turbo LLM model to use
PROMPT_DIR prompts Directory with .jinja templates

Project layout

.
├── main.py                     # CLI entry point (Typer)
├── cli/
│   ├── analyze.py              # Layout analysis command
│   ├── extract.py              # Structured extraction command
│   └── evaluate.py             # Scoring command
├── core/
│   ├── __init__.py             # Hyre orchestrator
│   ├── config.py               # Pydantic settings
│   ├── constants.py            # Role/content constants
│   ├── parsers.py              # PDFParser (pymupdf4llm)
│   ├── prompt.py               # JinjaPromptProvider
│   ├── schemas.py              # Pydantic schemas (GitHub)
│   ├── types.py                # Type aliases
│   └── providers/
│       ├── base.py             # Provider protocols
│       ├── chat.py             # OpenRouterProvider
├── core/prompts/
│   ├── layout.jinja            # Layout analysis prompt
│   ├── extract.jinja           # Structured extraction prompt
│   └── evaluate.jinja          # Resume scoring prompt
├── pyproject.toml
├── uv.lock
└── requirements.txt

What we fixed from Hiring Agent

We started from HackerRank's Hiring Agent and rebuilt most of it. Here is what we think it got wrong:

Too many entry points. Hiring Agent had score.py, pdf.py, github.py all doing overlapping things. You had to dig through the code to figure out which script to run. Hyre has three commands: analyze, extract, evaluate. One entry point (main.py), consistent flags.

No feedback while it runs. You ran score.py and stared at a blank terminal for 30 seconds. Hyre shows a spinner with status messages so you know it is actually working.

Raw JSON dumps. The output was unformatted JSON blobs. Hyre renders tables, trees, panels, and color-coded bars so you can actually read the results.

Single-use architecture. The old code mixed PDF parsing, LLM calls, GitHub fetching, and scoring into one tangled flow. Hyre splits these into a core module with clean interfaces. You can swap parsers, model providers, or prompt loaders without rewriting everything.

Prompt templates scattered. Templates were spread across files with no clear naming convention. Hyre keeps them in prompts/ with one file per command. The JinjaPromptProvider loads them automatically.

Template variables were not being passed. The {{ text_content }} variables in the prompts rendered as empty strings because nobody called template.render() with the resume text. The resume was sent in the user message but the system prompt had a blank where the resume should have been. Hyre passes the parsed text into the template so the LLM sees the full context.

GitHub overreach. Hiring Agent spends a lot of effort fetching GitHub profiles and classifying repos. That is useful but it should not be the main pipeline. Hyre keeps GitHub as a separate provider you can call if you want, not something baked into every resume scan.

We are not done. There is more to fix. But every change stays open source.

License

MIT © HackerRank

Acknowledgments

Hyre is built on Hiring Agent by HackerRank. Their open-source work made this possible. We are committed to keeping it going.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

hyre-0.1.0.tar.gz (23.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

hyre-0.1.0-py3-none-any.whl (23.2 kB view details)

Uploaded Python 3

File details

Details for the file hyre-0.1.0.tar.gz.

File metadata

  • Download URL: hyre-0.1.0.tar.gz
  • Upload date:
  • Size: 23.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.0

File hashes

Hashes for hyre-0.1.0.tar.gz
Algorithm Hash digest
SHA256 6c1a3cda7cdecc56359a296782c99e316c7dd4d9d27fdd033d5703576a554083
MD5 5eab234e1994c078637d0d498091908a
BLAKE2b-256 7bc7c629094707b0a15deb1bddc9dc080c2d592b144e640c9377f698943fb08f

See more details on using hashes here.

File details

Details for the file hyre-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: hyre-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 23.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.0

File hashes

Hashes for hyre-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 91afdbb13c67111ed87a155772627d8191b37c7ad6db2dd1f8a9e048626b568f
MD5 6099a92e930b4fac48b24db860b1ef48
BLAKE2b-256 c02bee1de02bb6c1c37941e1ddb2b20ac57dc840c04674397897a1067112bd87

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page