# Understanding the /rank Command and Batch-Scoring Workflow in AI Job Search

> Discover the purpose of the /rank command and its batch-scoring workflow in AI job search. It bridges data collection and application analysis by ranking job postings for a candidate. Learn more!

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

---

**The `/rank` command batch-scores newly scraped job postings against a candidate's fit framework to produce a ranked shortlist, serving as the critical bridge between the data collection and detailed application analysis stages.**

The `MadsLorentzen/ai-job-search` repository automates the end-to-end job search pipeline through a series of Claude commands. The `/rank` command operates as the intelligent filtering layer that transforms raw scraped data into a prioritized queue, enabling efficient prioritization before deeper evaluation.

## What Is the /rank Command?

The `/rank` command sits between the *scrape* stage (which gathers raw job postings into [`job_scraper/seen_jobs.json`](https://github.com/MadsLorentzen/ai-job-search/blob/main/job_scraper/seen_jobs.json)) and the *apply* stage (which conducts deep single-job analysis). Its primary function is to **batch-score all newly scraped postings** against the candidate's fit framework 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).

By evaluating multiple postings simultaneously, the command generates a ranked shortlist that users can feed into `/apply` for detailed preparation. This batch-processing approach ensures that only the most relevant opportunities advance to the resource-intensive application preparation phase.

## The 5-Step Batch-Scoring Workflow

According to the command specification in [`.claude/commands/rank.md`](https://github.com/MadsLorentzen/ai-job-search/blob/main/.claude/commands/rank.md), the workflow follows a strict 6-step pipeline:

### Step 0: Parse Input Arguments

The command first interprets CLI arguments to determine scope. Users can specify:

- `--all` : Force re-scoring of all non-applied jobs
- `--top <N>` : Return the top N results (default: 5)
- Focus keywords : Filter for specific domains like "data science" or "backend"

These parameters determine which entries in [`job_scraper/seen_jobs.json`](https://github.com/MadsLorentzen/ai-job-search/blob/main/job_scraper/seen_jobs.json) enter the processing queue.

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

The system loads two critical state files:

1. [`job_scraper/seen_jobs.json`](https://github.com/MadsLorentzen/ai-job-search/blob/main/job_scraper/seen_jobs.json) : Contains scraped job postings
2. `job_search_tracker.csv` : Tracks already-applied or manually-tracked jobs

The command builds an exclusion set from the tracker, ensuring already-processed jobs are ignored unless `--all` is specified.

### Step 2: Batch-Fetch and Score with Parallel Agents

This is the core processing stage. The workflow dispatches **general-purpose agents** in parallel, assigning approximately **5 jobs per agent** to balance concurrency with token budget constraints.

Each agent receives inline context containing:
- Job list (title, company, URL)
- Scoring rubric from [`04-job-evaluation.md`](https://github.com/MadsLorentzen/ai-job-search/blob/main/04-job-evaluation.md)

For each assigned job, agents perform:
- **WebFetch** retrieval with retry logic defined in [`.claude/skills/job-application-assistant/09-web-research.md`](https://github.com/MadsLorentzen/ai-job-search/blob/main/.claude/skills/job-application-assistant/09-web-research.md)
- Dimension scoring across four categories: **technical**, **experience**, **behavioral**, and **career**
- Veto evaluation for `location_verdict` and `language_gate`
- Deadline extraction and parsing

Agents return a structured JSON object containing scores, verdicts, strengths, gaps, and metadata.

### Step 3: Aggregate, Weight, and Rank

The orchestrator aggregates agent outputs and calculates weighted overall scores:

- **Technical** : 30%
- **Experience** : 25%
- **Behavioral** : 15%
- **Career** : 30%

Jobs map to verdict bands:
- **Strong Fit** : ≥ 75
- **Moderate Fit** : 50-74
- **Weak Fit** : 30-49
- **Poor Fit** : < 30

**Veto rules** apply strictly: `FAIL` on location or language excludes the job entirely, while `FLAG` entries remain in the pool but carry warning markers. The system also performs an **expiry sweep**, marking overdue deadlines as `expired` and adding urgency indicators (🔥) to approaching deadlines.

### Step 4: Update State in seen_jobs.json

The command writes additive fields back to [`job_scraper/seen_jobs.json`](https://github.com/MadsLorentzen/ai-job-search/blob/main/job_scraper/seen_jobs.json) for each processed job:

```json
{
  "status": "ranked",
  "rank_score": 78.5,
  "rank_verdict": "Strong Fit",
  "rank_date": "2024-09-01",
  "location_verdict": "PASS",
  "language_gate": "FLAG",
  "deadline": "2024-09-10",
  "strengths": ["Kubernetes experience", "Remote-first culture"],
  "gaps": ["No TypeScript", "No AWS certifications"]
}

```

Expired jobs receive `status: "expired"`. Notably, the system makes **no changes** to `job_search_tracker.csv` during this phase.

### Step 5: Present the Shortlist

Finally, the command emits a human-readable table displaying the ranked results. The default view shows the top 5 entries (configurable via `--top`), highlighting urgency markers, veto flags, and application URLs for immediate action.

## Batch-Scoring Mechanics and Architecture

### Parallel Agent Processing

The workflow achieves scalability through **job batching**. By splitting dozens of postings into groups of approximately five, the system leverages parallel processing while respecting API token limits. This architecture prevents the pipeline bottleneck that would occur with sequential single-job scoring.

### Data-Only Evaluation Scope

Unlike the `/apply` command, `/rank` performs **data-only scoring**. Agents evaluate strictly on posting text and candidate profile alignment. No external company research, salary lookups, or cultural deep-dives occur during batching—these resource-intensive operations remain the domain of the individual application preparation phase.

### Idempotency and Re-Ranking

The command implements idempotent behavior by default. Subsequent runs without `--all` skip jobs already carrying `status: "ranked"`, preventing redundant API calls. When candidates update their profiles or evaluation rubrics, the `--all` flag forces a **full re-score** of the entire pipeline, ensuring rankings reflect current fit criteria.

## Why the Batching Workflow Matters

**Scalability:** Scraping often returns dozens of new postings; sequential one-by-one scoring would create prohibitive latency. Parallel batching reduces total evaluation time by 80-90%.

**Consistency:** All jobs score against the **same snapshot** of the evaluation rubric. This ensures that a "Strong Fit" designation on Tuesday uses identical criteria to one assigned on Friday, enabling fair comparison across time-shifted scraping sessions.

**Traceability:** The persistent storage of veto fields, strengths, and gaps in [`seen_jobs.json`](https://github.com/MadsLorentzen/ai-job-search/blob/main/seen_jobs.json) creates an audit trail. Later commands like `/upskill` or `/apply` can reference these stored justifications to explain why specific jobs reached the shortlist or were excluded.

## Command Usage and Output Examples

### CLI Invocation Patterns

```bash

# Rank all new postings (default top 5)

> /rank

# Rank only “data science” related postings

> /rank data science

# Re-rank every non-applied job after profile update

> /rank --all

# Return a larger shortlist

> /rank --top 15

```

### Sample Agent Output Structure

The JSON returned by scoring agents in Step 2 follows this contract:

```json
{
  "key": "12345-abcde",
  "status": "scored",
  "scores": {
    "technical": 78,
    "experience": 65,
    "behavioral": 52,
    "career": 81
  },
  "location_verdict": "PASS",
  "language_gate": "FLAG",
  "language_note": "Requires fluent German (candidate B1)",
  "deadline": "2024-09-10",
  "strengths": ["Works with Kubernetes", "Remote-first culture"],
  "gaps": ["No TypeScript experience", "No AWS certifications"],
  "language": "en"
}

```

## Summary

- The `/rank` command filters scraped jobs through a **weighted scoring framework** (Technical 30%, Experience 25%, Behavioral 15%, Career 30%) to generate prioritized shortlists.
- It processes jobs in **parallel batches of ~5** per agent, fetching posting content via WebFetch with retry logic defined in [`09-web-research.md`](https://github.com/MadsLorentzen/ai-job-search/blob/main/09-web-research.md).
- **Veto rules** (`location_verdict`, `language_gate`) automatically exclude or flag jobs before they reach the final shortlist.
- State persistence occurs exclusively in [`job_scraper/seen_jobs.json`](https://github.com/MadsLorentzen/ai-job-search/blob/main/job_scraper/seen_jobs.json), leaving `job_search_tracker.csv` unchanged during ranking operations.
- The workflow supports **idempotent re-ranking** via the `--all` flag, allowing candidates to recalibrate scores after profile updates.
- All scoring rubrics and evaluation criteria derive 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).

## Frequently Asked Questions

### How does the /rank command differ from the /apply command?

The `/rank` command performs **batch evaluation** on many jobs simultaneously using only posting text and profile alignment, producing a prioritized list. The `/apply` command conducts **deep single-job analysis**, incorporating external company research, salary data, and tailored application strategy for one specific posting. Use `/rank` to decide *which* jobs deserve attention; use `/apply` to prepare *how* to approach them.

### What happens if a job fails the location or language veto?

Jobs receiving a `FAIL` verdict in `location_verdict` or `language_gate` are **automatically excluded** from the final shortlist and marked accordingly in [`seen_jobs.json`](https://github.com/MadsLorentzen/ai-job-search/blob/main/seen_jobs.json). Jobs receiving a `FLAG` verdict remain in the pool but carry warning annotations visible in the output table, allowing users to manually review borderline cases.

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

Yes. By default, `/rank` skips jobs already marked as `"ranked"` to save API costs. To force a complete re-evaluation after profile updates or rubric changes, invoke the command with the **`--all`** flag. This overrides the idempotency check and re-scores every non-applied job in the pipeline against your current criteria.

### How many jobs does each agent process in parallel?

Each general-purpose agent processes **approximately 5 jobs** per batch. This batch size balances parallel throughput with API token budget constraints, as defined in the orchestration logic within [`.claude/commands/rank.md`](https://github.com/MadsLorentzen/ai-job-search/blob/main/.claude/commands/rank.md). The system dynamically groups jobs to maximize concurrency while ensuring each agent receives sufficient context window for comprehensive evaluation.