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. 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: python 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: python 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 https://github.com/ANIRudH-lab-life/job-radar Landing page: https://anirudh-lab-life.github.io/job-radar/ 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