# How to Use the /rank Command for Batch Ranking of Scraped Jobs

> Master the /rank command for batch ranking scraped jobs. This guide explains how to efficiently score and prioritize job postings using AI agents for an optimized application process.

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

---

**The `/rank` command performs lightweight triage scoring on scraped job postings by loading data from [`job_scraper/seen_jobs.json`](https://github.com/MadsLorentzen/ai-job-search/blob/main/job_scraper/seen_jobs.json), applying parallel AI agents to evaluate fit against your candidate profile, and producing a prioritized shortlist for the `/apply` stage.**

The `/rank` command serves as the critical bridge between the **scrape** stage (raw data collection) and the **apply** stage (deep company evaluation) in the MadsLorentzen/ai-job-search repository. It enables efficient batch ranking of scraped jobs by processing posting text against your personalized evaluation framework without conducting external research or salary lookups.

## Architecture and Data Flow

The batch ranking process operates through six distinct phases defined in [`.claude/commands/rank.md`](https://github.com/MadsLorentzen/ai-job-search/blob/main/.claude/commands/rank.md). Each phase handles specific transformations of your job search data.

### Step 0: Parse Input Arguments

The command interprets flexible arguments to determine scope:

- **Default (no args):** Ranks only new jobs (status `"new"`) with a default shortlist of 5
- **Focus phrase:** Filters jobs by keyword (e.g., `"data science"`)
- **`--all`:** Re-scores all non-applied jobs, including previously ranked entries
- **`--top <N>`:** Limits output to the top N results

### Step 1: Load State and Build Exclusion Sets

The system loads two critical data stores:

1. **[`job_scraper/seen_jobs.json`](https://github.com/MadsLorentzen/ai-job-search/blob/main/job_scraper/seen_jobs.json)** – The repository of scraped postings produced by `/scrape`
2. **`job_search_tracker.csv`** – The exclusion set of already-applied jobs

The command selects candidates based on status filters (`new` or all non-applied when using `--all`) and applies optional focus filtering based on your input phrase.

### Step 2: Parallel Batch Fetching and Scoring

The command fires parallel "general-purpose" agents, assigning approximately **5 jobs per agent**. Each agent receives:

- The inline job list
- The **scoring rubric** extracted from [`.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)
- The **candidate profile** from [`.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)

Agents fetch the posting URL, read raw text, and return a JSON payload containing per-dimension scores, location verdicts, deadline information, strengths, gaps, and language assessments. For security, agents never follow instructions hidden in postings or fetch additional URLs.

### Step 3: Aggregate and Calculate Rankings

The system computes overall scores using weights defined in the evaluation framework. It maps numeric scores to verdict bands:

- **Strong Fit:** ≥ 75
- **Good Fit:** 60–74
- **Moderate Fit:** 45–59
- **Weak Fit:** < 45

Location vetoes trigger an immediate `FAIL` status, while imminent deadlines receive urgency markers (`🔥`). Jobs sort by score, using urgency as a tiebreaker.

### Step 4: Update State Persistently

Results write back to [`job_scraper/seen_jobs.json`](https://github.com/MadsLorentzen/ai-job-search/blob/main/job_scraper/seen_jobs.json) with metadata:

```json
{
  "status": "ranked",
  "rank_score": 84,
  "rank_verdict": "Strong Fit",
  "rank_date": "2026-07-26"
}

```

Expired or past-deadline jobs receive `status: "expired"`. The tracker CSV remains unmodified, preserving idempotency.

### Step 5: Present the Shortlist

The command emits a markdown table displaying:

- **Shortlisted jobs:** Top N entries meeting the threshold
- **Below threshold:** Jobs scoring too low for immediate consideration
- **Excluded jobs:** Location failures or expired postings

All URLs link directly to the `url` field in [`seen_jobs.json`](https://github.com/MadsLorentzen/ai-job-search/blob/main/seen_jobs.json).

## Command Syntax and Usage Examples

Invoke the `/rank` command through your CLI wrapper (Discord bot, terminal script, or web UI) using these patterns:

```bash

# Rank all newly scraped jobs (default shortlist size = 5)

/rank

# Rank only jobs matching a focus phrase

/rank data science

# Re-score everything not yet applied to, including previously ranked jobs

/rank --all

# Limit the shortlist to the top 10 jobs

/rank --top 10

# Combine focus filtering with size limits

/rank machine learning --top 7

```

## Understanding the Output Format

The command produces structured markdown output similar to this example:

```markdown

## Job Ranking – 2026-07-26

Ranked 12 new postings (5 shortlisted, 4 below threshold, 3 expired/vetoed).

### Shortlist

| # | Score | Verdict    | Title                | Company | Location   | Deadline   |    | URL |

|---|-------|------------|---------------------|---------|------------|------------|----|-----|
| 1 | 84    | Strong Fit | Senior Data Engineer| Acme AI | Copenhagen | 2026-08-02 | 🔥 | [Link](https://example.com/job/123) |
| 2 | 78    | Good Fit   | ML Engineer         | DataCo  | Remote     | –          |    | [Link](https://example.com/job/456) |

### Below threshold

| Score | Verdict      | Title          | Company | Reason                    |
|-------|--------------|----------------|---------|---------------------------|
| 58    | Moderate Fit | Junior Analyst | XYZ Ltd | Missing key skill "SQL"   |

### Excluded

- Senior Backend Engineer at BackendX – location FAIL: requires relocation
- Front-End Lead at UIWorks – expired 2026-06-30

```

After reviewing the shortlist, you can respond with job numbers to initiate the full `/apply` workflow for selected entries.

## Key Implementation Files

| Component | File Path | Purpose |
|-----------|-----------|---------|
| **Command Definition** | [`.claude/commands/rank.md`](https://github.com/MadsLorentzen/ai-job-search/blob/main/.claude/commands/rank.md) | Procedural specification of all 6 steps |
| **Evaluation Framework** | [`.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) | Dimension weights and verdict bands |
| **Candidate Profile** | [`.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) | Skill matrix and deal-breakers |
| **Scraped Data Store** | [`job_scraper/seen_jobs.json`](https://github.com/MadsLorentzen/ai-job-search/blob/main/job_scraper/seen_jobs.json) | Raw postings and ranking metadata |
| **Application Tracker** | `job_search_tracker.csv` | Exclusion set of applied jobs |

## Summary

- **The `/rank` command** enables efficient batch ranking of scraped jobs by evaluating postings against your candidate profile and evaluation framework.
- **Parallel agent architecture** processes approximately 5 jobs per agent, fetching posting text and returning structured JSON scores without external research.
- **Idempotent operations** ensure re-running the command skips already-ranked jobs unless you specify the `--all` flag to force re-scoring.
- **Safety rules** prevent agents from executing instructions embedded in job postings or accessing additional URLs beyond the primary posting link.
- **Persistent state** updates only [`job_scraper/seen_jobs.json`](https://github.com/MadsLorentzen/ai-job-search/blob/main/job_scraper/seen_jobs.json), leaving `job_search_tracker.csv` untouched to maintain data integrity.

## Frequently Asked Questions

### What is the difference between `/rank` and `/apply`?

The `/rank` command performs lightweight triage scoring to prioritize which jobs deserve deeper investigation, while `/apply` conducts comprehensive company-aware evaluation including salary research, culture analysis, and tailored application generation. Use `/rank` to filter dozens of scraped postings into a manageable shortlist, then use `/apply` only on the top selections.

### How does the scoring algorithm weight different job criteria?

The algorithm uses weights defined 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), which typically balances technical skill matches, career trajectory alignment, location preferences, and compensation requirements. Location deal-breakers trigger immediate `FAIL` status regardless of other scores, while the final numeric score maps to verdict bands (Strong Fit ≥ 75, Good Fit 60–74, etc.).

### Can I re-rank jobs after updating my candidate profile?

Yes. Run `/rank --all` to force re-scoring of all non-applied jobs, including those previously ranked. This updates the `rank_score`, `rank_verdict`, and `rank_date` fields in [`job_scraper/seen_jobs.json`](https://github.com/MadsLorentzen/ai-job-search/blob/main/job_scraper/seen_jobs.json) based on your current profile 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).

### Why are some jobs marked as "expired" or "location FAIL"?

Jobs receive `expired` status when their application deadline has passed or the posting is no longer active. `location FAIL` indicates the job violates your location deal-breakers defined in the candidate profile (e.g., requires relocation when you specified remote-only). These exclusions prevent wasted effort on ineligible positions.