# How Candidate Data Is Stored and Managed in the AI Job Search Framework

> Discover how candidate data is stored and managed in the AI Job Search Framework. Learn about structured Markdown files, interview setup, and profile resets.

- Repository: [Mads Lorentzen/ai-job-search](https://github.com/MadsLorentzen/ai-job-search)
- Tags: internals
- Published: 2026-08-31

---

**Candidate data in the AI Job Search Framework is stored as structured Markdown files under `.claude/skills/job-application-assistant/`, populated via the `/setup` interview command and cleared via `/reset profile`, ensuring complete separation from immutable framework logic.**

The AI Job Search Framework by MadsLorentzen treats candidate data as the single source of truth for all downstream job-search workflows. Unlike traditional database-driven applicant tracking systems, this open-source framework uses a file-based architecture where structured Markdown files store your identity, skills, and behavioral profiles alongside the code. Understanding how candidate data is stored and managed in the AI Job Search Framework ensures you can safely update, version-control, and migrate your information without corrupting the core engine.

## Core Storage Architecture: The Markdown-First Approach

The framework implements a **thin-pointer design** that strictly isolates candidate data from framework logic. Every rule-based file lives alongside a data-only counterpart, and the system only reads the data files during execution.

This separation occurs in two distinct locations:

- **Immutable framework logic**: Methodology, scoring rubrics, and command specifications reside in the repository root and `.claude/commands/`
- **Mutable candidate data**: Personal information populates files under `.claude/skills/job-application-assistant/` and the top-level [`CLAUDE.md`](https://github.com/MadsLorentzen/ai-job-search/blob/main/CLAUDE.md)

The [`tools/check_upstream_updates.py`](https://github.com/MadsLorentzen/ai-job-search/blob/main/tools/check_upstream_updates.py) script leverages this separation by comparing `framework_version` stamps in each file. When you pull upstream updates, the script only touches methodology sections while preserving your personal data blocks.

## The Five Data Categories and Their File Locations

Candidate information is partitioned into five logical categories, each persisted to a specific Markdown file path.

### Core Profile: Identity and Professional History

The **foundational candidate record** lives in [`.claude/skills/job-application-assistant/01-candidate-profile.md`](https://github.com/MadsLorentzen/ai-job-search/blob/main/.claude/skills/job-application-assistant/01-candidate-profile.md). This file contains structured sections for:

- Identity (name, location, contact)
- Education and certifications
- Professional experience
- Technical skills and specializations
- Languages and proficiencies
- References

The `/setup` command generates this file by parsing raw documents you place in the `documents/` folder (CVs, LinkedIn exports, diplomas).

### Behavioral Profile: Personality and Work Style

Psychometric assessments and work preferences populate [`.claude/skills/job-application-assistant/02-behavioral-profile.md`](https://github.com/MadsLorentzen/ai-job-search/blob/main/.claude/skills/job-application-assistant/02-behavioral-profile.md). This includes MBTI types, DISC profiles, strength inventories, and preferred work environments.

The behavioral data is created during the same `/setup` interview that builds the core profile, drawing from any behavioral assessments you provide in the `documents/` folder.

### Job Evaluation Criteria: Personalized Match Logic

Your specific career goals, constraints, and match priorities reside in [`.claude/skills/job-application-assistant/04-job-evaluation.md`](https://github.com/MadsLorentzen/ai-job-search/blob/main/.claude/skills/job-application-assistant/04-job-evaluation.md). Unlike the static profile files, this document contains **personalized tokens** such as `[YOUR_PRIMARY_SKILLS]` alongside static scoring dimensions.

The file serves as the configuration layer for the `/rank` and `/apply` commands, determining how the framework evaluates job postings against your qualifications.

### Supporting Assets: Templates and Prepared Content

Derived materials generated from your core profile populate several auxiliary files:

- [`.claude/skills/job-application-assistant/05-cv-templates.md`](https://github.com/MadsLorentzen/ai-job-search/blob/main/.claude/skills/job-application-assistant/05-cv-templates.md): Curated resume templates populated with your experience bullets
- [`.claude/skills/job-application-assistant/07-interview-prep.md`](https://github.com/MadsLorentzen/ai-job-search/blob/main/.claude/skills/job-application-assistant/07-interview-prep.md): Pre-built STAR stories drawn from your work history
- [`.claude/skills/job-application-assistant/search-queries.md`](https://github.com/MadsLorentzen/ai-job-search/blob/main/.claude/skills/job-application-assistant/search-queries.md): Saved job board queries tailored to your skills

These files are filled by `/setup` from the same source documents used to build the primary profiles.

### Human-Readable Summary: The Top-Level Mirror

The [`CLAUDE.md`](https://github.com/MadsLorentzen/ai-job-search/blob/main/CLAUDE.md) file in the repository root serves as a **human-readable summary** of all structured skill files. Claude writes this file during `/setup` and maintains it as a mirror of the data under `.claude/skills/job-application-assistant/`.

Unlike the resettable profile files, [`CLAUDE.md`](https://github.com/MadsLorentzen/ai-job-search/blob/main/CLAUDE.md) is not touched by `/reset profile`. You must delete it manually to achieve a completely clean slate.

## Data Lifecycle: From Import to Reset

Candidate data flows through a four-stage lifecycle that ensures data hygiene while preserving framework integrity.

### Import Phase: Gathering Raw Artifacts

Begin by placing unstructured career artifacts into the `documents/` folder. Accepted formats include:

- PDF resumes and CVs
- LinkedIn profile exports
- Scanned diplomas and certifications
- Past application drafts
- Reference letters

The framework treats this folder as a staging area; the actual structured storage happens in the next phase.

### Interview Phase: The /setup Command

Running `/setup` launches a **Claude Code interview** specified in [`.claude/commands/setup.md`](https://github.com/MadsLorentzen/ai-job-search/blob/main/.claude/commands/setup.md). During this session:

1. Claude parses all files in `documents/`
2. The system asks follow-up questions to resolve ambiguities
3. Claude writes the structured Markdown files ([`01-candidate-profile.md`](https://github.com/MadsLorentzen/ai-job-search/blob/main/01-candidate-profile.md), [`02-behavioral-profile.md`](https://github.com/MadsLorentzen/ai-job-search/blob/main/02-behavioral-profile.md), etc.) with your specific data

This command effectively transforms unstructured documents into queryable, structured candidate data.

### Active Use: Downstream Consumption

All job-search commands read the same Markdown files to perform work:

- `/rank [url]`: Reads [`01-candidate-profile.md`](https://github.com/MadsLorentzen/ai-job-search/blob/main/01-candidate-profile.md) and [`04-job-evaluation.md`](https://github.com/MadsLorentzen/ai-job-search/blob/main/04-job-evaluation.md) to compute a triage score for job postings
- `/apply`: Generates cover letters using skills from [`01-candidate-profile.md`](https://github.com/MadsLorentzen/ai-job-search/blob/main/01-candidate-profile.md) and work examples from [`07-interview-prep.md`](https://github.com/MadsLorentzen/ai-job-search/blob/main/07-interview-prep.md)
- `/interview`: Produces behavioral questions using [`02-behavioral-profile.md`](https://github.com/MadsLorentzen/ai-job-search/blob/main/02-behavioral-profile.md)

Because these commands only read the data files, you can safely modify the framework logic without affecting your stored profile.

### Reset Phase: Data Hygiene Commands

When your career data becomes stale, two commands manage cleanup:

1. **`/reset profile`**: Rewrites [`01-candidate-profile.md`](https://github.com/MadsLorentzen/ai-job-search/blob/main/01-candidate-profile.md), [`02-behavioral-profile.md`](https://github.com/MadsLorentzen/ai-job-search/blob/main/02-behavioral-profile.md), [`04-job-evaluation.md`](https://github.com/MadsLorentzen/ai-job-search/blob/main/04-job-evaluation.md), and auxiliary files to their blank templates, preserving the framework scaffolding
2. **`/reset documents`**: Clears the raw source files from the `documents/` folder

The reset commands follow the specifications in [`.claude/commands/reset.md`](https://github.com/MadsLorentzen/ai-job-search/blob/main/.claude/commands/reset.md) and ensure that personalized tokens revert to placeholder values while immutable methodology sections remain intact.

## Programmatic Access to Candidate Data

Because candidate data is stored as plain Markdown, you can read and manipulate it using standard file I/O operations without requiring database connections.

### Reading the Candidate Profile

Access your core profile directly from Python:

```python
from pathlib import Path

profile_path = Path(
    ".claude/skills/job-application-assistant/01-candidate-profile.md"
)
profile_md = profile_path.read_text(encoding="utf-8")
print(profile_md.splitlines()[:15])   # Display the Identity section

```

### Updating a Single Field Programmatically

Add new certifications without rerunning `/setup`:

```python
import re, pathlib

file = pathlib.Path(
    ".claude/skills/job-application-assistant/01-candidate-profile.md"
)

text = file.read_text()

# Insert a new skill under "Technical Skills → Programming & ML"

new_line = "- **Rust** (Intermediate): actix-web, tokio"
text = re.sub(
    r"(### Programming & ML\n(?:- .*\n)*)",

    r"\1" + new_line + "\n",
    text,
)
file.write_text(text)

```

### Executing Reset via CLI

Trigger the reset workflow from the repository root:

```bash

# Start fresh

claude
/reset profile    # Clears all candidate-data files to templates

```

### Consuming Data in Downstream Commands

The framework automatically reads candidate data when executing search commands:

```bash
claude
/rank https://jobindex.dk/job/1234567

```

This command loads your structured profile to calculate match scores against the specific posting.

## Safeguarding Data Integrity During Framework Updates

The [`tools/check_upstream_updates.py`](https://github.com/MadsLorentzen/ai-job-search/blob/main/tools/check_upstream_updates.py) utility ensures that pulling new framework versions never overwrites your personal data. The script compares `framework_version` stamps embedded in each Markdown file, identifying only the methodology sections that have changed upstream.

Because candidate data lives only in the markdown files under `.claude/skills/job-application-assistant/`, while the repository root contains immutable methodology, you can safely pull updates and run the check tool to merge framework improvements without risking profile corruption.

## Summary

- **Candidate data is stored as structured Markdown** in `.claude/skills/job-application-assistant/` (files `01-` through `07-` plus [`search-queries.md`](https://github.com/MadsLorentzen/ai-job-search/blob/main/search-queries.md)), not in a database.
- **The `/setup` command** processes raw documents from the `documents/` folder to populate these files via an interactive interview.
- **The top-level [`CLAUDE.md`](https://github.com/MadsLorentzen/ai-job-search/blob/main/CLAUDE.md)** serves as a human-readable mirror of your profile but is not cleared by reset commands.
- **`/reset profile`** sanitizes candidate data while preserving framework scaffolding, making it safe to refresh your career information.
- **Plain-text storage** enables programmatic manipulation with standard file I/O and version control via Git without binary database files.

## Frequently Asked Questions

### What happens to my candidate data when I update the framework?

Your data remains safe because the framework separates immutable methodology from mutable candidate files. The [`tools/check_upstream_updates.py`](https://github.com/MadsLorentzen/ai-job-search/blob/main/tools/check_upstream_updates.py) script compares `framework_version` stamps in each file and only updates the rule-based sections, leaving your personal information in [`01-candidate-profile.md`](https://github.com/MadsLorentzen/ai-job-search/blob/main/01-candidate-profile.md) and related files untouched.

### Can I manually edit my candidate profile without running /setup again?

Yes. Because candidate data is stored as plain Markdown, you can directly edit [`.claude/skills/job-application-assistant/01-candidate-profile.md`](https://github.com/MadsLorentzen/ai-job-search/blob/main/.claude/skills/job-application-assistant/01-candidate-profile.md) or any other data file using a text editor. The downstream commands (`/rank`, `/apply`, `/interview`) will read your changes immediately without requiring an interview session.

### Where should I place my raw CV and LinkedIn export for the /setup command?

Place all raw career artifacts—PDFs, LinkedIn exports, diplomas, and past applications—in the `documents/` folder at the repository root. The `/setup` command scans this directory, parses the unstructured text, and writes the structured data to the appropriate files under `.claude/skills/job-application-assistant/`.

### What is the difference between /reset profile and /reset documents?

`/reset profile` clears the structured Markdown files ([`01-candidate-profile.md`](https://github.com/MadsLorentzen/ai-job-search/blob/main/01-candidate-profile.md), [`02-behavioral-profile.md`](https://github.com/MadsLorentzen/ai-job-search/blob/main/02-behavioral-profile.md), etc.) by rewriting them to blank templates while preserving the framework scaffolding. `/reset documents` clears the raw source files you originally placed in the `documents/` folder. Use `/reset profile` when your career data becomes stale; use `/reset documents` to clean up the staging area after successful import.