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:
job_scraper/seen_jobs.json– The repository of scraped postings produced by/scrapejob_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 - The candidate profile from
.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 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
/rankcommand 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
--allflag 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, leavingjob_search_tracker.csvuntouched 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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →