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

The /rank command performs lightweight triage scoring on scraped job postings by loading data from 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. 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 – 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:

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 with metadata:

{
  "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.

Command Syntax and Usage Examples

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


# 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:


## 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 Procedural specification of all 6 steps
Evaluation Framework .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 Skill matrix and deal-breakers
Scraped Data Store 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, 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, 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 based on your current profile in .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.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →