cd /news/developer-tools/under-the-hood-of-jobradar-8-job-sou… · home topics developer-tools article
[ARTICLE · art-83495] src=dev.to ↗ pub= topic=developer-tools verified=true sentiment=· neutral

Under the Hood of JobRadar: 8 Job Sources, a 1.7B Model, Zero Cloud

A developer built JobRadar, a CLI tool that searches eight job sources concurrently and scores listings against a user's profile using a local 1.7B parameter LLM (qwen3-1.7b) running on the user's CPU, with no cloud APIs or subscriptions. The tool pulls roles from company career pages via Greenhouse and Ashby APIs without authentication, and ranks jobs based on skills, experience, salary, and remote fit, with a SQLite cache to avoid duplicates.

read4 min views1 publishedAug 2, 2026

Job searching is tab hell. You open six boards, re-read the same listings, and pay $30/month for tools that are just feed aggregators wearing an "AI-powered" sticker.

So I built JobRadar — a CLI tool that searches 8 job sources concurrently and scores every listing against your profile using a local LLM that runs on your own CPU. No API keys, no subscriptions, no resume leaving your machine.

The launch post covered the what. This one covers the how.

The whole thing is one linear pipeline:

query + profile.yaml
      │
      ▼
8 source adapters (concurrent) ──► normalized Job objects
      │
      ▼
local LLM scores each job 0-100 (skills, experience, salary, remote fit)
      │
      ▼
seen-jobs cache (SQLite, 7-day)  ──► ranked table + results.csv

In code, the search phase looks like this:

from concurrent.futures import ThreadPoolExecutor, as_completed

def search_all(sources, query, limit, max_pages):
    jobs = []
    with ThreadPoolExecutor(max_workers=len(sources)) as pool:
        futures = {pool.submit(s.search, query, limit, max_pages): s
                   for s in sources}
        for future in as_completed(futures):
            jobs.extend(future.result())
    return jobs

Eight adapters, one interface, all running in parallel. A query that used to take me 20 minutes of tab-hopping finishes in under a minute.

Five of the sources are classic job board APIs:

The interesting two are Greenhouse and Ashby. These are applicant tracking systems that a huge chunk of tech companies use — and they have public career-page APIs. No auth, no scraping. You just hit their job board endpoint with a company slug:

class GreenhouseSearch(Source):
    def search(self, query, limit, max_pages):
        jobs = []
        for company in self.companies:          # e.g. gitlab, figma, stripe
            url = f"https://boards-api.greenhouse.io/v1/boards/{company}/jobs"
            resp = requests.get(url, timeout=10)
            jobs.extend(normalize_greenhouse(resp.json()))
        return jobs

That means JobRadar pulls roles straight from company career pages — GitLab, Figma, Stripe, OpenAI, Anthropic, Linear — without an account or an API key on any of them. The company list is a YAML file you can edit:

greenhouse:
  - gitlab
  - figma
  - discord
  - shopify
  - stripe

LinkedIn scraping exists but is off by default — it depends on undocumented HTML that breaks constantly, and it might violate their ToS. I'd rather ship without it and be honest about the tradeoff than bundle a ToS risk into the default path.

This is the part people ask about the most. Every other tool I found uses cloud APIs (Claude, OpenAI) for scoring — your resume and search history go to someone else's server, and you pay per token. JobRadar runs qwen3-1.7b (a 1.1 GB GGUF) on your machine via Ollama or llama.cpp.

The rater auto-detects whatever local LLM server is running by scanning the standard ports:

_DEFAULT_PORTS = [
    ("http://localhost:11434", "Ollama"),    # Ollama default
    ("http://localhost:8080",  "llama.cpp"), # llama.cpp default
    ("http://localhost:1234",  "LM Studio"), # LM Studio default
]

If you have a bigger model installed, it picks that up too — you can override with --llm-model qwen3:8b

and scoring gets smarter at the cost of speed.

Each job gets scored 0-100 across four dimensions — skills match, experience fit, salary fit, remote fit — with the model's reasoning captured so you can see why a job scored the way it did. Rating calls run concurrently (3 by default, --max-concurrency

to tune) with retry logic for the occasional malformed JSON response.

Honest take: a 1.7B model is a good filter, not an oracle. It catches "this says Python but is actually a sales role" reliably. It does not have your gut feel about company culture, and it shouldn't — that's the point. The score is a starting point, not a verdict.

Job boards republish the same listings constantly. JobRadar keeps a SQLite database of seen jobs (~/.jobradar/seen_jobs.db

) with a 7-day window, so every run only surfaces what's new. --cache-days 30

to stretch it, --no-cache

to see everything again.

The CLI is the core, but there's a companion web dashboard — a FastAPI backend, SQLite storage, and a dark-mode SPA with a Kanban pipeline. Jobs flow from Discovered to Reviewing to Applied to Interviewing, cards are color-coded by match score, and there's a live terminal-style activity log showing the LLM scoring progress as it happens. It reads like a terminal because the whole product is terminal-first.

Job

dataclass at the boundary and every downstream step gets simpler.

curl -fsSL https://raw.githubusercontent.com/ANIRudH-lab-life/job-radar/main/setup.sh | bash

Or browse the source: https://github.com/ANIRudH-lab-life/job-radar

Landing page: https://anirudh-lab-life.github.io/job-radar/

MIT licensed. Built with Python, Rich, FastAPI, SQLite, and a whole lot of tabs closed.

Also published: the launch post

── more in #developer-tools 4 stories · sorted by recency
── more on @jobradar 3 stories trending now
sponsored brought to you by zahid.host 4,200+ EU-deployed projects
reading about agents? ship yours in a single git push.

Run your AI side-project on zahid.host

EU-based hosting, git-push deploys, automatic HTTPS, no cold starts. Free tier with a custom domain — perfect for shipping the agent you just read about.

$git push zahid main
Live at https://your-agent.zahid.host
Get free account → Pricing
from €0/mo · no card required
LIVE [news/under-the-hood-of-jo…] indexed:0 read:4min 2026-08-02 ·