# How the /upskill Command Performs Skill Gap Analysis and Generates Learning Plans

> Discover how the /upskill command analyzes skill gaps and creates personalized learning plans using hard-skill diffing and AI synthesis. Get curated resources and time estimates for efficient upskilling.

- Repository: [Mads Lorentzen/ai-job-search](https://github.com/MadsLorentzen/ai-job-search)
- Tags: how-to-guide
- Published: 2026-07-26

---

**The `/upskill` command executes a two-pass skill gap analysis—combining hard-skill diffing with LLM-driven synthesis—to generate prioritized learning plans with curated study resources and time estimates.**

The `/upskill` command in the [MadsLorentzen/ai-job-search](https://github.com/MadsLorentzen/ai-job-search) repository automates the process of identifying missing competencies between a candidate's current profile and job market requirements. Defined entirely within [`.claude/skills/upskill/SKILL.md`](https://github.com/MadsLorentzen/ai-job-search/blob/main/.claude/skills/upskill/SKILL.md), this workflow supports both aggregate analysis across all tracked applications and targeted analysis for specific job postings.

## Overview of the /upskill Workflow

The command operates through a nine-step pipeline defined in the skill specification file. At its core, the workflow compares candidate data against job requirements, weights gaps by relevance, and produces actionable documentation.

The system recognizes two operational modes:

- **Aggregate mode**: Analyzes all entries in `job_search_tracker.csv` to identify market-wide skill trends
- **Targeted mode**: Analyzes a single job posting provided via URL argument

## Step-by-Step Skill Gap Analysis

### Mode Detection and Initialization

The workflow first determines execution context by checking for a URL argument. According to lines 25-31 of [`.claude/skills/upskill/SKILL.md`](https://github.com/MadsLorentzen/ai-job-search/blob/main/.claude/skills/upskill/SKILL.md), if a user invokes `/upskill https://example.com/job/123`, the system enters targeted mode and generates a slug from the job title and company for the report filename. Without a URL, the command defaults to aggregate mode.

### Data Loading and Profile Comparison

In **aggregate mode**, the system reads `job_search_tracker.csv`, extracting `role`, `company`, and `fit_rating` for each tracked position while loading the baseline candidate profile from [`01-candidate-profile.md`](https://github.com/MadsLorentzen/ai-job-search/blob/main/01-candidate-profile.md). It also checks the `upskill/` directory for existing reports to enable differential analysis between runs.

In **targeted mode**, the workflow fetches the specific posting via **WebFetch**, extracts the full job description, and loads only the candidate profile—bypassing the tracker data entirely.

### Pass 1 – Hard-Skill Diffing

The first analytical pass extracts technical requirements and compares them against the candidate profile. As implemented in lines 49-67 of the specification:

- **Aggregate analysis**: Infers skills from `role`, `sector`, and `notes` columns, optionally fetching source URLs for detail. Constructs a **skill frequency map** weighted by `(100-fit_rating)/100`, where lower fit ratings indicate higher skill urgency.
- **Targeted analysis**: Uses explicit skill lists from the fetched posting with equal weighting for all listed competencies.

The system performs generous matching to remove skills already present in the candidate profile. The remaining items form the **hard-skill gap list**, sorted by weighted score in aggregate mode or by required-to-preferred priority in targeted mode.

### Pass 2 – LLM Synthesis

The second pass employs a large language model to identify gaps that structured diffing misses. As defined in lines 68-81, the LLM reasons about:

- **Domain knowledge** gaps (`[domain]`)
- **Soft-skill** gaps (`[soft]`)
- **Tooling and process** gaps (`[tooling]`)
- **Credential and certification** gaps (`[credential]`)

Each synthesized gap receives a type tag and undergoes deduplication against Pass 1 results before inclusion.

### Building the Gap Heatmap

Lines 83-105 of [`.claude/skills/upskill/SKILL.md`](https://github.com/MadsLorentzen/ai-job-search/blob/main/.claude/skills/upskill/SKILL.md) specify the heatmap construction. The system merges Pass 1 and Pass 2 results into a markdown table with four priority levels:

- **Critical**
- **High**
- **Medium**
- **Low**

Priority assignment depends on frequency and weight in aggregate mode, or explicit job language (required vs. preferred) in targeted mode. The heatmap renders to the terminal before learning plan generation begins, allowing immediate visibility into competency gaps.

## Learning Plan Generation

### Resource Curation via Web Search

For every **Critical** and **High** priority gap—and **Medium** gaps when fewer than five total gaps exist—the workflow executes automated resource discovery. According to lines 106-133, the system:

1. Executes **WebSearch** with year-specific queries (e.g., `"best Kubernetes course 2025 site:reddit.com"`)
2. Selects 2-3 high-quality resources including courses, official documentation, and books
3. Lists each resource with name, URL, and one-line justification

### Study Direction and Time Estimates

Each learning entry includes a **study direction** tailored to existing knowledge (e.g., "skip Docker basics") and an **estimated time** to proficiency. Resources group under thematic headings such as "Cloud & Infrastructure" or "MLOps" to create structured learning paths.

### Priority-Based Study Ordering

Lines 144-162 specify the final study sequencing algorithm. The system generates an ordered table respecting:

- **Dependencies** (e.g., AWS networking after AWS fundamentals)
- **Priority tiers** (Critical → High → Medium)
- **Quick wins** (short-duration gaps placed early)
- **Domain knowledge** (placed later in the sequence)

## Report Persistence and File Structure

The workflow saves comprehensive markdown reports to the `upskill/` directory. As defined in lines 168-39 of the specification:

- **Aggregate reports**: [`upskill/report-YYYY-MM-DD.md`](https://github.com/MadsLorentzen/ai-job-search/blob/main/upskill/report-YYYY-MM-DD.md)
- **Targeted reports**: `upskill/report-YYYY-MM-DD-<company-slug>-<role-slug>.md`

If previous aggregate reports exist, the system appends a "Since Last Report" diff section highlighting progress. Guardrails defined in lines 40-48 enforce rules against fabricating resources and mandate current-year search queries.

## Usage Examples

### Aggregate Mode Analysis

Analyze all tracked job applications:

```text
/upskill

```

Sample output excerpt:

```markdown

# Upskill Report — 2026-07-26

## Gap Heatmap

| Priority | Skill / Area                | Type     | Gap Source |
|----------|----------------------------|----------|------------|
| Critical | Kubernetes                 | Hard     | 4/5 jobs, score 3.2 |
| High     | Security domain knowledge  | Domain   | LLM synthesis |
| High     | CI/CD pipelines            | Tooling  | LLM synthesis |

```

### Targeted Mode Analysis

Analyze a specific posting:

```text
/upskill https://example.com/job/12345

```

### Sample Learning Plan Entry

```markdown

### Cloud & Infrastructure

**Kubernetes** `[Hard]` — ~20h
- [Kubernetes for Absolute Beginners – KodeKloud](https://kodekloud.com) — hands-on labs, widely recommended
- [Official Kubernetes Docs: Concepts](https://kubernetes.io/docs/concepts/) — reference material
- [The Kubernetes Book – Nigel Poulton](https://leanpub.com/the-kubernetes-book)

Study direction: You already know Docker; skip containers basics and start with pod scheduling.

```

## Summary

- The `/upskill` command performs **two-pass analysis** (hard-skill diff + LLM synthesis) to identify technical and non-technical gaps
- **Aggregate mode** analyzes `job_search_tracker.csv` with frequency weighting, while **targeted mode** evaluates single URLs
- The system generates **priority-ordered heatmaps** (Critical/High/Medium/Low) based on job requirements and fit ratings
- **Automated WebSearch** curates current-year study resources with time estimates and personalized study directions
- Reports persist to `upskill/report-YYYY-MM-DD*.md` with optional differential tracking between analysis runs

## Frequently Asked Questions

### What is the difference between aggregate and targeted mode in /upskill?

Aggregate mode analyzes all entries in `job_search_tracker.csv` to identify market-wide skill trends, weighting gaps by `(100-fit_rating)/100` to prioritize skills needed for lower-fit positions. Targeted mode accepts a specific job URL, fetches that posting via WebFetch, and analyzes only the explicit requirements listed in that single job description.

### How does the skill gap heatmap determine priority levels?

The heatmap assigns **Critical**, **High**, **Medium**, or **Low** priority based on frequency and weight calculations in aggregate mode—where skills appearing across multiple low-fit jobs receive higher priority—or based on explicit job language (required vs. preferred) in targeted mode. The LLM synthesis pass can elevate domain knowledge and soft skills to High priority regardless of hard-skill frequency.

### Where are the generated learning plans stored?

Learning plans save automatically to the `upskill/` directory as markdown files. Aggregate analyses generate [`upskill/report-YYYY-MM-DD.md`](https://github.com/MadsLorentzen/ai-job-search/blob/main/upskill/report-YYYY-MM-DD.md), while targeted analyses create `upskill/report-YYYY-MM-DD-<company-slug>-<role-slug>.md`. The system checks for previous aggregate reports to include a "Since Last Report" diff section showing progress over time.

### Does /upskill only analyze technical skills?

No. While Pass 1 focuses on hard-skill extraction, Pass 2 employs an LLM to identify **domain knowledge**, **soft skills**, **tooling/process** gaps, and **credentials**. These non-technical gaps receive type tags (e.g., `[domain]`, `[soft]`) and integrate into the final heatmap and learning plan alongside technical requirements.