Files
ai-job-search/.claude/skills/job-scraper/SKILL.md
T
Ayobami Adegoke fce2cf23c0 feat: add /rank command to triage scraped jobs into a ranked shortlist (#43)
/scrape finds and dedupes postings; /apply evaluates one at a time in
depth. Nothing connects the two ends: after a scrape returns 20 jobs, the
user eyeballs a table to decide where to spend /apply effort. /rank is the
bridge: batch-score every new posting against the fit framework and return
a ranked shortlist.

How it works:

- Selects jobs with status "new" from job_scraper/seen_jobs.json (--all
  re-ranks everything unapplied; a focus argument filters), excluding
  anything already in job_search_tracker.csv
- Dispatches parallel general-purpose agents (~5 jobs each) that WebFetch
  each posting and score the five dimensions from 04-job-evaluation.md.
  The rubric (skill match areas, career goals, deal-breakers) is passed
  inline per the same token-efficiency rules /apply uses; agents score
  only from actually fetched content and mark dead postings expired,
  never guessing from a title
- Triage depth by design: posting text vs. profile only - no company
  research, no salary lookups. /apply's Step 1 evaluation stays
  authoritative and always re-runs on handoff
- Aggregates with the framework's 30/25/15/30 weighting and verdict
  bands; location deal-breakers veto regardless of score; deadlines
  within 7 days get urgency flags and win ties
- Updates seen_jobs.json additively (status "ranked"/"expired" plus
  rank_score/rank_verdict/rank_date) so /scrape dedup keeps working;
  the tracker is read-only. Re-running is idempotent

Integration: job-scraper SKILL.md documents the new status values and
suggests /rank after large scrape batches; README (commands list, file
tree, quick-start step 4).
2026-07-07 17:31:31 +02:00

126 lines
4.5 KiB
Markdown

---
name: job-scraper
description: >
Scrapes Danish job sites for new positions matching your profile. Deduplicates across runs.
Triggers on: job scrape, find jobs, search jobs, new jobs, job search, scrape jobs, /scrape
allowed-tools: Read, Write, Edit, Glob, Grep, WebFetch, WebSearch, Agent, AskUserQuestion
---
# Job Scraper
---
## How It Works
This skill searches multiple Danish job sites using targeted queries based on your profile, deduplicates against previously seen jobs and the application tracker, and presents new matches with a quick fit assessment.
## Invocation
The user triggers this skill by saying things like:
- "Find new jobs"
- "Scrape for jobs"
- "Any new positions?"
- "/scrape"
Optional arguments:
- A focus area, e.g. "/scrape data science" or "/scrape geophysics"
- "broad" to run all search categories, e.g. "/scrape broad"
---
## Execution Steps
### Step 0: Load State
1. Read `job_scraper/seen_jobs.json` (create if missing - start with `{"seen": {}}`)
2. Read `job_search_tracker.csv` to extract already-applied companies+roles
3. Read `search-queries.md` (this directory) for the search strategy
### Step 1: Search
Run **WebSearch** queries from `search-queries.md`. By default, run the top 3 priority categories. If the user said "broad", run all categories.
If the user specified a focus area (e.g. "data science"), prioritize queries from that category.
For each search:
- Use `WebSearch` with site-specific queries (jobindex.dk, linkedin.com/jobs, karriere.dk, etc.)
- Target your configured geographic area
- Look for postings from the last 14 days
### Step 2: Fetch & Parse
For each promising result from Step 1:
- Use `WebFetch` to retrieve the job posting page
- Extract: **job title**, **company**, **location**, **posting date** (or "recent"), **URL**, **key requirements** (brief), **application deadline** (if listed)
- Skip if the URL or company+title combo already exists in `seen_jobs.json`
- Skip if the company+role already appears in `job_search_tracker.csv`
### Step 3: Quick Fit Assessment
For each new job, do a rapid fit check (NOT the full evaluation from `04-job-evaluation.md` - just a quick signal):
- **High match**: Role directly involves your core skills
- **Medium match**: Role is adjacent to your experience
- **Low match**: Role requires significant skills you lack
### Step 4: Deduplicate & Store
1. Add ALL fetched jobs (new and skipped) to `seen_jobs.json` with structure:
```json
{
"seen": {
"<url_or_company_title_key>": {
"title": "...",
"company": "...",
"url": "...",
"first_seen": "YYYY-MM-DD",
"fit": "high/medium/low",
"status": "new/skipped/evaluated/ranked/expired"
}
}
}
```
2. Only present jobs NOT already in the seen list or tracker.
### Step 5: Present Results
Present new jobs in a table sorted by fit (high first):
```
## New Job Matches - YYYY-MM-DD
Found X new positions (Y high, Z medium, W low match).
| # | Fit | Title | Company | Location | Deadline | URL |
|---|-----|-------|---------|----------|----------|-----|
| 1 | High | ... | ... | ... | ... | [Link](...) |
### High-Match Highlights
For each high-match job, add 2-3 bullet points:
- Why it matches your profile
- Key requirements to check
- Any red flags
```
After presenting, ask:
> "Want me to evaluate any of these in detail? Just give me the number(s)."
If the user picks a number, invoke the **job-application-assistant** skill workflow (fit evaluation first, then CV + cover letter if approved).
If the run found many new jobs (roughly 8+), also suggest `/rank` - it batch-scores all new postings against the full fit framework and returns a ranked shortlist, which beats eyeballing a long table. (`/rank` sets the `ranked` and `expired` status values in `seen_jobs.json`; treat both as already-seen for dedup purposes.)
### Step 6: Update Tracker (Optional)
If the user decides to apply to any job, add a row to `job_search_tracker.csv`.
---
## Important Rules
1. **Never fabricate job postings.** Only present jobs found via actual WebSearch/WebFetch results.
2. **Respect deduplication.** Always check seen_jobs.json AND job_search_tracker.csv before presenting.
3. **Focus on configured geographic area.** Skip jobs that require relocation or are clearly outside commute range.
4. **Only open positions.** Skip postings with expired deadlines or those marked as closed.
5. **Be efficient with WebFetch.** Don't fetch every search result - use titles and snippets to pre-filter before fetching.
6. **Parallel searches.** Use the Agent tool or parallel WebSearch calls to speed up the search phase.