# How the Development Mode Caching Mechanism Works in the Hiring Agent

> Understand the hiring agent's development mode caching mechanism. Learn how deterministic JSON file storage caches résumés and GitHub API responses while production bypasses cache operations.

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

---

**The development mode caching mechanism uses deterministic JSON file storage to cache parsed résumés and GitHub API responses when `DEVELOPMENT_MODE` is `True`, while bypassing all cache operations entirely in production.**

The `interviewstreet/hiring-agent` repository implements a lightweight file-based caching layer that accelerates local development without compromising production data freshness. When `DEVELOPMENT_MODE` is enabled in [`config.py`](https://github.com/interviewstreet/hiring-agent/blob/main/config.py), the system caches expensive operations—specifically résumé parsing and external API calls—to disk, allowing developers to iterate quickly on scoring logic without reprocessing unchanged inputs.

## Overview of the Development Mode Caching Mechanism

The mechanism is controlled by the `DEVELOPMENT_MODE` boolean flag defined in [`config.py`](https://github.com/interviewstreet/hiring-agent/blob/main/config.py). When set to `True` (the default for local development), the code activates two distinct cache implementations: one for résumé parsing in [`score.py`](https://github.com/interviewstreet/hiring-agent/blob/main/score.py) and another for GitHub API calls in [`github.py`](https://github.com/interviewstreet/hiring-agent/blob/main/github.py) (lines 35-50). Both systems share a common pattern: they check for existing cache files before performing expensive operations, load JSON data when available, and write results only after successful processing.

## Resume Parsing Cache in score.py

In [`score.py`](https://github.com/interviewstreet/hiring-agent/blob/main/score.py) (lines 227-260), the development mode caching mechanism stores the JSON representation of parsed résumés to avoid redundant PDF processing.

### Cache File Structure and Naming

Cache files are named deterministically based on the input PDF filename, following the pattern `resumecache_*.json`. The system stores these files in a `cache/` directory that is created on demand using `os.makedirs(os.path.dirname(cache_filename), exist_ok=True)`.

### Reading and Writing Resume Cache

At the start of execution, the code checks for an existing cache:

```python
if DEVELOPMENT_MODE and os.path.exists(cache_filename):
    print(f"Loading cached data from {cache_filename}")
    try:
        cached_data = json.loads(Path(cache_filename).read_text(encoding="utf-8"))
        loaded_resume = JSONResume(**cached_data)
        cache_loaded = True
    except Exception as e:
        print(f"⚠️ Warning: Invalid cache file {cache_filename}: {e}")
        print("Ignoring cache and reprocessing PDF...")
        os.remove(cache_filename)

```

After successful parsing, the cache is written only if the data was not loaded from cache:

```python
if not cache_loaded:
    # ... parsing logic ...

    if resume_data_is_valid:
        os.makedirs(os.path.dirname(cache_filename), exist_ok=True)
        Path(cache_filename).write_text(
            json.dumps(resume_dict, ensure_ascii=False, indent=2), encoding="utf-8"
        )

```

## GitHub API Response Cache in github.py

The [`github.py`](https://github.com/interviewstreet/hiring-agent/blob/main/github.py) module implements a similar development mode caching mechanism for GitHub REST API calls, storing responses as `gh_githubcache_*.json` files.

### Cache Lookup and Storage

Before making HTTP requests, the code generates a deterministic filename using `_create_cache_filename(api_url, params)` and checks for cached data:

```python
cache_filename = _create_cache_filename(api_url, params)
if DEVELOPMENT_MODE and os.path.exists(cache_filename):
    print(f"Loading cached GitHub data from {cache_filename}")
    try:
        cached_data = json.loads(Path(cache_filename).read_text(encoding="utf-8"))
        if cached_data:
            return 200, cached_data
    except Exception as e:
        print(f"⚠️ Warning: Error reading cache file {cache_filename}: {e}")
        os.remove(cache_filename)

```

When a request succeeds with `status_code == 200`, the response is cached:

```python
if DEVELOPMENT_MODE and status_code == 200:
    os.makedirs("cache", exist_ok=True)
    Path(cache_filename).write_text(
        json.dumps(data, ensure_ascii=False, indent=2), encoding="utf-8"
    )

```

## Error Handling and Cache Invalidation

Both caching implementations include robust error handling for corrupted cache files. If `json.loads()` raises an exception during cache reading, the code immediately removes the invalid file using `os.remove(cache_filename)` and falls back to the original processing logic—reprocessing the PDF in [`score.py`](https://github.com/interviewstreet/hiring-agent/blob/main/score.py) or retrying the HTTP request in [`github.py`](https://github.com/interviewstreet/hiring-agent/blob/main/github.py). This ensures that malformed cache entries never block execution and are automatically regenerated on the next run.

## Production vs. Development Behavior

When `DEVELOPMENT_MODE` is set to `False` in production environments, all `if DEVELOPMENT_MODE ...` blocks are skipped entirely. This means:

- No cache files are read, ensuring fresh data on every execution
- No cache files are written, preventing disk I/O and storage of potentially sensitive data
- All PDFs are reprocessed and all API calls are made live

This dual-mode behavior guarantees that the development mode caching mechanism never affects production runs, maintaining data consistency and eliminating stale cache risks in deployed environments.

## Summary

- The development mode caching mechanism activates only when `DEVELOPMENT_MODE` is `True` in [`config.py`](https://github.com/interviewstreet/hiring-agent/blob/main/config.py)
- **Résumé parsing** is cached in [`score.py`](https://github.com/interviewstreet/hiring-agent/blob/main/score.py) using deterministic `resumecache_*.json` files based on PDF filenames
- **GitHub API responses** are cached in [`github.py`](https://github.com/interviewstreet/hiring-agent/blob/main/github.py) using `gh_githubcache_*.json` files based on request URLs and parameters
- Cache files are stored in the `cache/` directory created on demand via `os.makedirs(..., exist_ok=True)`
- Corrupted caches are automatically deleted and regenerated, ensuring system resilience
- Production environments bypass all caching logic entirely, guaranteeing fresh data

## Frequently Asked Questions

### Where is the development mode flag defined?

The `DEVELOPMENT_MODE` boolean is defined in [`config.py`](https://github.com/interviewstreet/hiring-agent/blob/main/config.py) at the repository root. It defaults to `True` for local development and must be explicitly set to `False` in production environments to disable all caching operations.

### How are cache filenames generated to ensure consistency?

Cache filenames are deterministic. For résumés, the name derives from the input PDF filename. For GitHub API calls, the `_create_cache_filename()` function generates names based on the API URL and request parameters. This ensures identical inputs always map to the same cache file, providing consistent cache hits across runs.

### What happens if a cache file becomes corrupted?

If reading a cache file raises an exception (such as invalid JSON), the code catches the error, prints a warning message, deletes the corrupted file using `os.remove(cache_filename)`, and proceeds to reprocess the original input. This automatic invalidation prevents crashes and ensures data integrity.

### Does the cache mechanism affect production performance?

No. When `DEVELOPMENT_MODE` is `False`, all cache-related code blocks are bypassed entirely. The application never checks for, reads, or writes cache files in production, ensuring that every execution fetches fresh data and processes inputs from scratch.