Skip to content

Generates A Resume for You (GARY) is an agentic ai who tailors your resume according to a job description

Notifications You must be signed in to change notification settings

praneethravuri/gary

Repository files navigation

Gary - AI-Powered Resume Tailoring System

An intelligent resume tailoring system powered by CrewAI that analyzes job descriptions and automatically customizes your resume to match specific job requirements while maintaining authenticity and readability.

Motivation

Job applications require tailored resumes that highlight relevant skills and experiences for each position. Manually customizing resumes for every application is time-consuming and inconsistent. Gary automates this process using AI agents that:

  • Analyze job descriptions to extract key requirements, skills, and company culture indicators
  • Tailor your master resume to emphasize relevant experience and integrate important keywords naturally
  • Validate the tailored resume for ATS compatibility and human readability
  • Generate professional Word documents ready for submission
  • Track all applications in Google Sheets for easy management

Features

  • Multi-Agent AI System: Three specialized agents working sequentially

    • Job Analyst: Extracts skills, responsibilities, qualifications, tone, and cultural values from job descriptions
    • Resume Tailor: Customizes resume content to align with job requirements while maintaining authenticity
    • Resume Validator: Scores keyword integration, ATS compatibility, and readability before final generation
  • Intelligent Resume Customization: Naturally integrates job-specific keywords and phrases without sounding robotic

  • ATS Optimization: Ensures resumes pass Applicant Tracking Systems while remaining human-readable

  • Automated Document Generation: Creates formatted Word documents using customizable templates

  • Application Tracking: Logs all job applications to Google Sheets with job details and application dates

  • Comprehensive Validation: Provides detailed feedback on resume quality with actionable suggestions

Example Output

Here's what a generated resume looks like:

Example Resume Output

Professional, ATS-optimized resume document generated by Gary

Project Structure

gary/
├── assets/
│   └── example_resume.jpg       # Example resume output image
├── data/
│   └── resume.json              # Your master resume data
├── templates/
│   └── resume_word_template.docx # Word document template
├── resumes/                     # Generated resume documents (output)
├── src/
│   └── gary/
│       ├── config/
│       │   ├── agents.yaml      # Agent configurations
│       │   └── tasks.yaml       # Task definitions
│       ├── tools/
│       │   └── resume_word_doc_tool.py
│       ├── utils/
│       │   ├── clean_job_description.py
│       │   ├── google_sheets.py
│       │   ├── read_json.py
│       │   ├── result_parser.py
│       │   └── resume_word_doc_generator.py
│       ├── config.py            # Path configurations
│       ├── crew.py              # CrewAI agent & task definitions
│       ├── exceptions.py        # Custom exceptions
│       ├── main.py              # Entry point
│       └── models.py            # Pydantic data models
├── .env                         # Environment variables
├── googleSheetsCredentials.json # Google service account credentials
├── pyproject.toml               # Project dependencies
└── README.md

Setup Instructions

1. Prerequisites

  • Python >= 3.10, < 3.14
  • uv package manager (recommended) or pip

2. Installation

Install uv if you haven't already:

pip install uv

Clone the repository and install dependencies:

cd gary
crewai install

Or using uv directly:

uv sync

3. Configure Environment Variables

Create a .env file in the project root with the following structure:

# OpenRouter API Configuration (or use OpenAI directly)
OPENROUTER_API_KEY=your_openrouter_api_key_here
OPENROUTER_BASE_URL=https://openrouter.ai/api/v1

# Google Sheets Configuration
GOOGLE_SHEETS_ID=your_google_sheets_id_here

How to get these values:

  • OPENROUTER_API_KEY: Sign up at OpenRouter and generate an API key
    • Or use OpenAI directly by modifying crew.py to use OpenAI's API
  • GOOGLE_SHEETS_ID: Found in your Google Sheets URL: https://docs.google.com/spreadsheets/d/{SHEET_ID}/edit

4. Setup Google Sheets Integration

Create a Google Cloud Service Account

  1. Go to Google Cloud Console
  2. Create a new project or select an existing one
  3. Enable the Google Sheets API:
    • Navigate to "APIs & Services" > "Library"
    • Search for "Google Sheets API"
    • Click "Enable"
  4. Create a service account:
    • Go to "APIs & Services" > "Credentials"
    • Click "Create Credentials" > "Service Account"
    • Fill in service account details and click "Create"
    • Skip optional permissions and click "Done"
  5. Generate credentials JSON:
    • Click on the created service account
    • Go to the "Keys" tab
    • Click "Add Key" > "Create New Key"
    • Select "JSON" and click "Create"
    • Download the JSON file

Configure Credentials

  1. Rename the downloaded JSON file to googleSheetsCredentials.json
  2. Place it in the project root directory
  3. The file should have this structure:
{
  "type": "service_account",
  "project_id": "your-project-id",
  "private_key_id": "key-id",
  "private_key": "-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----\n",
  "client_email": "your-service-account@your-project.iam.gserviceaccount.com",
  "client_id": "client-id",
  "auth_uri": "https://accounts.google.com/o/oauth2/auth",
  "token_uri": "https://oauth2.googleapis.com/token",
  "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
  "client_x509_cert_url": "cert-url"
}

Setup Google Sheets

  1. Create a new Google Sheet or use an existing one
  2. Share the sheet with the service account email (found in client_email in the JSON file)
    • Give it "Editor" permissions
  3. Copy the Sheet ID from the URL and add it to your .env file

Google Sheets Tracker

After generating each resume, the system automatically logs the job application to Google Sheets. The following fields from the JobDetails model are written:

Field Source Description Example
Date Applied job_details.date_applied Auto-generated current date in MM-DD-YYYY format 10-02-2025
Company Name job_details.company_name Company hiring for the position TechCorp
Job Title job_details.job_title Position title Senior Software Engineer
Location job_details.location Job location San Francisco, CA
Job ID job_details.job_id Optional job identifier (empty if not provided) ENG-2024-123
Job Description job_details.job_description Full cleaned job description text We are seeking a Senior...
Status Hardcoded Application status Done

Example Google Sheet:

Date Applied Company Name Job Title Location Job ID Job Description Status
10-02-2025 TechCorp Senior Software Engineer San Francisco, CA ENG-2024-123 We are seeking a Senior Software Engineer with expertise in Python and cloud technologies... Done
09-28-2025 StartupXYZ Full Stack Developer Remote Looking for a Full Stack Developer proficient in React and Node.js... Done
09-25-2025 BigCorp DevOps Engineer New York, NY DEV-456 Join our DevOps team to build scalable infrastructure... Done

The sheet will be populated automatically - you don't need to create the columns manually

5. Setup Resume Data

Create your master resume in data/resume.json following this structure:

{
  "header": {
    "name": "Your Full Name",
    "phone": "+1 (XXX) XXX-XXXX",
    "email": "your.email@example.com",
    "location": "City, State, Country",
    "links": [
      {
        "platform": "GitHub",
        "url": "https://github.com/yourusername"
      },
      {
        "platform": "LinkedIn",
        "url": "https://linkedin.com/in/yourusername"
      },
      {
        "platform": "Portfolio",
        "url": "https://yourportfolio.com"
      }
    ]
  },
  "professional_summary": {
    "summary": "Your professional summary highlighting your experience, skills, and expertise. This will be customized per job application."
  },
  "work_experience": [
    {
      "title": "Job Title",
      "company": "Company Name",
      "startDate": "Month Year",
      "endDate": "Present",
      "responsibilities": [
        "Detailed accomplishment or responsibility with metrics",
        "Another achievement with quantifiable results",
        "Technical contribution with specific technologies and impact"
      ]
    }
  ],
  "skills": [
    {
      "category": "Programming Languages",
      "items": ["Python", "JavaScript", "Go"]
    },
    {
      "category": "Frameworks & Libraries",
      "items": ["React", "FastAPI", "Node.js"]
    },
    {
      "category": "Databases",
      "items": ["PostgreSQL", "MongoDB", "Redis"]
    },
    {
      "category": "Cloud Technologies",
      "items": ["AWS", "GCP"]
    },
    {
      "category": "Developer Tools",
      "items": ["Docker", "Kubernetes", "Git"]
    }
  ],
  "education": [
    {
      "degree": "Degree Name, Major",
      "institution": "University Name",
      "startDate": "Month Year",
      "endDate": "Month Year",
      "coursework": ["Relevant Course 1", "Relevant Course 2"]
    }
  ],
  "projects": [
    {
      "name": "Project Name",
      "description": "Detailed project description highlighting technologies used, problem solved, and impact/results."
    }
  ]
}

Important Notes:

  • Include as much detail as possible in your master resume
  • Use specific metrics and achievements
  • The AI will select and emphasize the most relevant parts for each job
  • The location in the header will be automatically updated to match the job location

6. Customize Word Template (Optional)

The Word document template is located at templates/resume_word_template.docx. This template uses Jinja2 syntax for variable substitution.

Template Structure

Here's the Jinja2 template used to generate the resume. You can customize this template according to your needs:

{{ header.name }}
{{ header.location }} | {{ header.phone }} | {{ header.email }}
{% for link in header.links %}{{ link.url | replace("http://", "") }}{% if not loop.last %} | {% endif %}{% endfor %}

PROFESSIONAL SUMMARY
{{ resume_content.professional_summary.summary }}

WORK EXPERIENCE
{% for exp in resume_content.work_experience %}
{{ exp.title}}, {{ exp.company }}    {{ exp.startDate }} — {{ exp.endDate }}
{%- for resp in exp.responsibilities %}
{{ resp }}{% endfor %}
{% endfor %}

EDUCATION
{% for edu in resume_content.education %}
{{ edu.degree }}, {{ edu.institution }}    {{ edu.startDate }} —  {{ edu.endDate }}
{% if edu.coursework %}
Coursework: {%- for course in edu.coursework %}{{ course }}{% if not loop.last %}, {% endif %}{% endfor %}
{% endif %}
{%- endfor -%}

SKILLS
{% for skill in resume_content.skills %}
{{ skill.category }}: {% for item in skill['items'] %}{{ item }}{% if not loop.last %}, {% endif %}{% endfor %}
{%- endfor %}

PROJECTS
{% for proj in resume_content.projects %}
{{ proj.name }}: {{ proj.description }}
{%- endfor %}

How to Customize

  1. Open templates/resume_word_template.docx in Microsoft Word
  2. Modify the template:
    • Change fonts, colors, and formatting
    • Adjust spacing and layout
    • Rearrange sections (e.g., put Skills before Work Experience)
    • Add or remove sections
  3. Preserve the Jinja2 placeholders (text within {{ }} and {% %})
  4. Save the file as .docx format

Customization Tips:

  • Keep Jinja2 syntax intact for dynamic content generation
  • Use Word's styles for consistent formatting
  • Test with sample data to ensure proper rendering
  • Adjust margins and spacing for optimal page usage

How It Works

Resume Generation Flow

  1. Input Collection: The system prompts you for job details via CLI:

    • Company name
    • Job title
    • Location
    • Job ID (optional)
    • Job description (paste multi-line, type 'END' to finish)
  2. Job Analysis: The Job Analyst agent:

    • Extracts technical, soft, and management skills
    • Identifies key responsibilities and qualifications
    • Analyzes company tone and cultural values
    • Returns structured job analysis
  3. Resume Tailoring: The Resume Tailor agent:

    • Customizes professional summary for the specific role
    • Emphasizes relevant work experiences
    • Integrates keywords naturally into responsibilities
    • Selects most applicable skills and projects
    • Returns tailored resume content
  4. Validation: The Resume Validator agent:

    • Analyzes keyword integration rate
    • Scores ATS compatibility (0-100)
    • Scores human readability (0-100)
    • Identifies strengths, weaknesses, and provides suggestions
    • Returns validation report with overall score
  5. Document Generation:

    • Combines tailored content with your header info
    • Updates location to match job location
    • Renders Word document from template
    • Saves to resumes/ directory with naming: {name}_{company}_{job_title}_{job_id}.docx
  6. Application Tracking:

    • Logs job details to Google Sheets
    • Records date applied, company, title, location, and status

AI Agents

The system uses three specialized CrewAI agents:

Agent Model Role Temperature
Job Analyst Gemini 2.5 Flash Extract structured insights from job descriptions 0.2 (precise)
Resume Tailor Claude Sonnet 4 Customize resume content naturally and strategically 0.4 (balanced)
Resume Validator Gemini 2.5 Flash Validate quality, ATS compatibility, readability 0.2 (precise)

Usage

Running the Application

From the project root directory:

crewai run

Or using the installed script:

gary

Or using Python directly:

python -m gary.main

Example Workflow

$ crewai run

================================================================================
JOB DETAILS INPUT
================================================================================
Company Name: TechCorp
Job Title: Senior Software Engineer
Location: San Francisco, CA
Job ID (optional, press Enter to skip): ENG-2024-123

Job Description (paste below, then type 'END' on a new line and press Enter):
We are seeking a Senior Software Engineer with expertise in Python and cloud technologies...
[paste full job description]
END

✓ Job details collected for TechCorp - Senior Software Engineer (Applied: 10-02-2025)

[Agent execution logs...]

================================================================================
RESUME VALIDATION REPORT
================================================================================
Passed Validation: True
Overall Score: 92/100
Ready for Generation: True

Keyword Integration Rate: 87.5%
Keywords Integrated: 35/40
ATS Score: 94/100
Human Readability Score: 90/100

Strengths:
  ✓ Natural integration of technical keywords
  ✓ Strong quantifiable achievements
  ✓ Well-aligned with job requirements

Weaknesses:
  ✗ Missing mention of specific AWS services mentioned in job description

Suggestions:
  → Consider adding specific AWS service experience if applicable

================================================================================
GENERATING WORD DOCUMENT
================================================================================
✓ Resume generated successfully: C:\projects\gary\resumes\john_doe_TechCorp_Senior_Software_Engineer_ENG-2024-123.docx

✓ Job details logged to Google Sheets

Output

  • Word Document: Professional resume saved in resumes/ directory
  • Google Sheets: Job application logged automatically
  • Validation Report: Detailed feedback displayed in terminal
  • Logs: Execution logs saved in logs.txt

Customization

Modifying Agent Behavior

Edit agent configurations in src/gary/config/agents.yaml:

  • Adjust agent roles, goals, and backstories
  • Modify agent instructions and constraints

Modifying Task Instructions

Edit task configurations in src/gary/config/tasks.yaml:

  • Customize task descriptions and expected outputs
  • Adjust validation criteria and scoring

Changing AI Models

Edit src/gary/crew.py to change models:

llm=llm_config("openrouter/google/gemini-2.5-flash", 0.2)

Available models (via OpenRouter):

  • openrouter/anthropic/claude-sonnet-4
  • openrouter/google/gemini-2.5-flash
  • openrouter/openai/gpt-4
  • Many more at OpenRouter Models

Troubleshooting

Google Sheets Authentication Errors

  • Verify googleSheetsCredentials.json is in the project root
  • Ensure the service account email has Editor access to the sheet
  • Check that GOOGLE_SHEETS_ID in .env matches your sheet URL

Template Rendering Issues

  • Verify templates/resume_word_template.docx exists
  • Ensure Jinja2 placeholders in template match model fields
  • Test template with sample data

API Rate Limiting

  • OpenRouter has rate limits; consider upgrading plan for heavy usage
  • Adjust max_iter in agent configurations to reduce API calls

Resume Generation Fails

  • Check that data/resume.json follows the exact schema
  • Validate JSON syntax using a JSON validator
  • Ensure all required fields are present

License

This project is open source and available for personal and commercial use.

Contributing

Contributions are welcome! Please feel free to submit pull requests or open issues for bugs and feature requests.

Credits

Built with: