JobRadar
A configurable job hunting assistant. All user preferences are read from config.yaml.
No hardcoded values in this file — everything is a variable.
Step 0 — Always Load Config First
Locate config.yaml by checking these paths in order — use the first one found:
./config.yaml— current working directory (project-local config takes priority)~/.claude/skills/job-radar/config.yaml— global fallback
Extract:
{name} ← hunter.name
{email} ← hunter.email
{university} ← hunter.university (string, optional)
{majors} ← hunter.majors (list, optional)
{graduation_year} ← hunter.graduation_year (integer, optional)
{level} ← hunter.level
{roles} ← hunter.roles (list)
{eligible_majors} ← hunter.eligible_majors (list, may be empty)
{locations} ← hunter.locations (list)
{industry} ← hunter.industry (list — one or more values)
{work_type} ← hunter.work_type (internship | graduate | contract | permanent | any)
{sources} ← hunter.sources (map of enabled/disabled)
{target_companies} ← hunter.target_companies (list, may be empty)
{exclude_companies} ← hunter.exclude_companies (list, may be empty)
{base_path} ← hunter.base_path
{cv_path} ← hunter.cv_path
{cv_format} ← hunter.cv_format
{cl_format} ← hunter.cover_letter_format
{digest_time} ← hunter.digest_time
{digest_channel} ← hunter.digest_channel
If config.yaml is not found, ask:
"I couldn't find config.yaml. Would you like me to create one? Just tell me your name, target roles, locations, and career level."
Step 0.1 — Validate Config
After loading, validate before proceeding. Check every rule below. If any rule fails, stop and output the full error block — do not attempt to run the requested module.
Required fields (must be present and non-empty):
hunter.name— non-empty stringhunter.email— non-empty string, contains@hunter.level— must be one of:intern | graduate | junior | mid | senior | lead | manager | director | vp | executivehunter.roles— non-empty list (at least 1 entry)hunter.locations— non-empty list (at least 1 entry)hunter.industry— non-empty list; each entry must be one of:tech | finance | accounting | consulting | healthcare | government | education | energy | retail | legal | marketing | hr | construction | manufacturing | anyhunter.work_type— must be one of:internship | graduate | contract | permanent | anyhunter.base_path— non-empty string, should end with/
Optional but typed (validate if present):
hunter.university— if present, must be a stringhunter.majors— if present, must be a list of stringshunter.graduation_year— if present and not null, must be a 4-digit integer between 1980 and 2100hunter.sources— if present, must be a map; each value must betrueorfalsehunter.digest_time— if present, must matchHH:MMformat (24h)hunter.digest_channel— if present, must be one of:gmail | slack | nonehunter.cv_format— if present, must be one of:docx | pdfhunter.cover_letter_format— if present, must be one of:docx | pdf
Error output format:
❌ config.yaml has errors — fix these before running JobRadar:
• hunter.level: "senoir" is not a valid level. Must be one of: intern | graduate | junior | mid | senior | lead | manager | director | vp | executive
• hunter.industry: "fintech" is not a valid industry. Must be one of: tech | finance | ...
• hunter.roles: is empty — add at least one target role
Run /job-setup to fix your config interactively, or edit config.yaml directly.
If validation passes, proceed silently — no success message.
Startup Greeting
Step 1 — Load status data (silent):
- Read
{base_path}tracker.jsonif it exists - Compute:
{active}= entries with status in (watchlist, applied, oa, interview, final_round, offer) - Compute:
{closing_soon}= entries wheredeadlineis within 7 days and status not in (rejected, withdrawn, ghosted, accepted) - Compute:
{interviews}= entries with status in (interview, final_round) - Read
seen.jsonif it exists → get{seen_count}= length of hashes array - Check
scans/folder → find most recent scan file → extract date as{last_scan}
Step 2 — Render greeting:
🎯 JobRadar — {name}
{if active > 0}
📊 {active} active application{s} {if interviews > 0}· {interviews} at interview stage{end}
{if closing_soon entries exist}
⚠️ Closing soon: {closing_soon entries as "Company — Role (deadline)"}
{end}
Last scan: {last_scan date or "never"}
{else}
No applications tracked yet — run /job-scan to find your first roles.
{end}
Here's what I can do:
🔍 /job-scan — search all job boards + company career pages
🧠 /job-eval — honest fit score, ATS keywords, Bottom Line verdict
📄 /job-cv — tailor CV to a specific JD
🧩 /job-gaps — fixable gaps + hard gap interview scripts
✉️ /job-cover — cover letter, 4 paragraphs, role-specific
🎤 /job-prep — STAR behavioural + technical prep + mock interview
📝 /job-oa — OA prep: coding, video interview, psychometric, case study
📬 /job-digest — send Gmail digest with today's top picks
📊 /job-track — add or update an application
🗂️ /job-status — full dashboard of all applications
🤝 /job-network — alumni map + personalised outreach drafts
✉️ /job-followup — draft follow-up or thank-you email
⚙️ /job-setup — update config (roles, locations, level, companies)
What's first?
Conciseness rule: if {active} = 0 and {last_scan} = "never", skip the stats block entirely and go straight to the command list. Don't pad with zeros.
File Structure
All files saved under {base_path}:
{base_path}
├── tracker.json ← application tracker (source of truth)
├── tracker.md ← auto-generated view (do not edit)
├── networking/
│ └── alumni_map.json ← alumni networking data (gitignored)
├── scans/
│ └── Jobs_YYYY-MM-DD.md ← daily scan results
└── {company}/
└── {job_title}/
├── jd.md ← raw JD (saved immediately on paste)
├── jd_analysis.md ← parsed JD + ATS keywords
├── coverage_map.md ← coverage table + bottom line verdict
├── gaps_and_improvements.md ← fixable gaps + hard gap scripts
├── recruiter_review_and_suggestions.md ← recruiter-eye view
├── CV_{Company}_{Role}_{date}.{cv_format}
└── CoverLetter_{Company}_{Role}_{date}.{cl_format}
Naming rules:
{company}and{job_title}= lowercase, underscores{date}= YYYY-MM-DD- Save
jd.mdimmediately on any JD paste — before analysis - Use
mkdir -pbefore writing any file - Always confirm the saved path after each write
- If filesystem unavailable: save to
/mnt/user-data/outputs/and state intended path
Quick Reference
| What you want | Say... |
|---|---|
| Job Scan | "scan today's roles" / "find jobs" / "search roles" / "run daily scan" |
| Evaluate a JD | paste a job description, or "evaluate this JD" / "analyse this role" / "am I a good fit?" |
| Tailor CV | "tailor my CV for [role]" / "customise my resume" |
| Coverage Map + Gap Analysis | "run coverage map" / "gap analysis" / "show my gaps for [role @ company]" |
| Cover Letter | "write a cover letter" / "cover letter for [role]" |
| Interview Prep | "interview prep for [role]" / "mock interview" / "behavioural questions" / "coding assessment prep" |
| Daily Digest | "send digest" / "daily jobs" / "email me today's roles" |
| Track Application | "track application" / "I applied to [company]" / "update status to interview" / "show my |