If you have looked for a remote role recently, you know the routine.
You wake up, open 40 browser tabs across Ashby, Lever, Greenhouse, Remotive, Welcome to the Jungle, We Work Remotely, and the monthly Hacker News Who is Hiring thread. Half the "remote" listings secretly say US Only - Must reside in Texas in paragraph four. Another third are ghost jobs reposted every Tuesday.
When I looked for tools to automate this, every commercial "AI job copilot" had the same three problems:
- Another $29 to $49/month subscription at the exact moment you are looking for work.
- Your resume and personal data live on someone else's cloud.
- The double-billing trap: if you look at open-source tools, almost all of them require a paid, pay-per-token OpenAI or Anthropic API key, even though you already pay $20/month for a ChatGPT Plus, Claude Pro, or Gemini subscription.
I wanted something local, fast, and private that ran on my own machine. So over the last few weeks, I built and open-sourced Remote Job Hunter (rjh).
It is a local command center written in Python (standard library for the core engine + FastAPI and SQLite WAL) that scans 51+ job sources in parallel, scores every offer against a single profile.yaml, generates a 1-page ATS-safe PDF resume per company, and works even if you do not have an API key.
I just pushed v0.2 to GitHub, and I am looking for developers and job seekers to test it and tear it apart so I can make v0.3 better.
Built for Any Profession (Tech or Non-Tech, Remote or On-Site)
Despite the repo name (remote-job-hunter), the engine is completely domain-agnostic. It does not assume you are a software engineer, and it does not force you to look for remote-only roles:
search: # A nurse in Lyon (on-site) # A remote RevOps / Python engineer
titles: {primary: [infirmier, IDE]} # healthcare, finance, sales, HR... # [automation engineer, revops]
work_mode: {remote: any, cities: [Lyon]} # on-site, hybrid, or 100% remote # {remote: required}
Whether you are a nurse in Lyon (profile.non-tech.example.yaml), an accountant in Paris, a sales manager, or a backend engineer, dropping your PDF resume into the Command Center automatically extracts your domain skills and calibrates the search and 1-page ATS resume generator for your field.
1. The "Wait, why do I need an API key?" realization
When I shared the first prototype with a friend who is a nurse in Lyon (not a developer), she asked a simple question: "I already have ChatGPT on my phone. Why do I have to create a developer account and put in a credit card for an API key?"
She was right. API keys are great for unattended cron jobs, terrible for normal people.
That conversation led to Zero-API-Key Manual Mode:
51+ job sources ─▶ deterministic heuristic filter ─▶ 10 offers bundled into ONE prompt
│
scores, pitches & PoW diagrams ◀─ paste JSON back ◀─ paste into ChatGPT / Claude / Gemini
Here is how it works in practice:
-
rjh scanpulls offers from all your configured sources in parallel and runs a fast, deterministic local scorer (rjh/heuristic.py) that checks title match, location eligibility (Europe,Global,US Restricted), seniority, language, and your custom hard rules. - If you have an API key (
Gemini,OpenAI,Anthropic,Groq,Mistral,OpenRouter) or a localOllamamodel, it evaluates the top candidates automatically. - If you don't have an API key (or if your free quota hits
429), it automatically falls back to Manual Mode. You click Export a batch in the UI, paste the prompt into the ChatGPT/Claude/Gemini tab you already use, and paste the JSON reply back.
Handling truncated chat responses without losing work
Anyone who has pasted a large prompt into a web chat knows the main failure mode: the model stops generating at token 3,800 and leaves you with half a JSON array.
Instead of failing with JSONDecodeError, the parser in rjh/analysis.py salvages every completed JSON object from the truncated stream, saves those scores to SQLite immediately, and generates a follow-up ticket containing only the missing job IDs:
def salvage_json_objects(raw_text: str) -> list[dict]:
"""Extracts all complete top-level JSON objects from a truncated LLM array."""
decoder = json.JSONDecoder()
results = []
idx = 0
length = len(raw_text)
while idx < length:
brace = raw_text.find("{", idx)
if brace == -1:
break
try:
obj, end = decoder.raw_decode(raw_text, brace)
if isinstance(obj, dict) and "id" in obj:
results.append(obj)
idx = end
except json.JSONDecodeError:
idx = brace + 1
return results
Nothing gets lost, and you never re-run offers that were already scored.
2. Two-Stage Triage + Proof-of-Work Architecture Diagrams
Early on, I tried asking the LLM to score a job and write a custom pitch in a single pass. It was slow, burned tokens on mediocre roles, and produced generic pitches.
I split the pipeline into two distinct stages:
-
Stage 1 (Fast Triage): Evaluates up to 20 pre-filtered jobs per batch. Returns a
fit_score(0.0to10.0), detected tech stack, and a 1-sentence reason. -
Stage 2 (Deep Dossier for scores >= 7.5): Only for the roles worth applying to, the engine generates:
- A 3-paragraph tailored pitch grounded in your actual metrics from
profile.yaml. - A Proof-of-Work (
Mermaid.js) architecture diagram proposing a concrete technical workflow for that company's stack, rendered directly inside the modal so you can walk through it during an interview. - A short founder/hiring-manager DM with a 1-click LinkedIn X-Ray search link.
- A 3-paragraph tailored pitch grounded in your actual metrics from
3. Solving the ATS Resume Problem (cv_tailor.py)
When you apply on Workday, Taleo, Greenhouse, Lever, or Ashby, fancy two-column resumes with sidebars, progress bars, or floating boxes often get scrambled into unreadable text streams.
On the other hand, plain .txt-style resumes look awful when a human recruiter actually opens the PDF.
I built cv_tailor.py to solve both at once:
-
100% single-column linear DOM flow (
Header -> Summary -> Core Stack -> Experience -> Education) so legacy and modern ATS parsers read every line in the exact right order. - Editorial typography (Newsreader serif headers + Plus Jakarta Sans body) that fits strictly on 1 page A4.
-
Zero hallucination rule: It extracts the exact technical keywords from the job description (
n8n,Python,PostgreSQL,HubSpot,REST APIs), reorders your existing bullet points so the most relevant ones sit at the top, and bolds matching terms without inventing skills or metrics you don't have. -
Built-in 7-point ATS self-audit: Every generated PDF is inspected with
pypdfbefore returning a score (100/100, 1 page A4 verified) and automatically syncs with the 1-click Playwright form pre-filler.
4.Killing my own "Cyberpunk Terminal" UI
I have a confession: the first version of the dashboard looked like a 1990s hacker movie. Everything was neon green, uppercase monospace, glowing text shadows, [ BRACKETS EVERYWHERE ], and emojis on every button.
After staring at it for three days, my eyes hurt. A tool you use every morning shouldn't feel like a video game HUD.
I stripped out all the neon glow, brackets, and fake hacker jargon, and rebuilt the interface around a calm Linear / Raycast / Editorial aesthetic:
-
Dark Mode (
#09090B) and Warm Paper Light Mode (#FAF8F5) switched via the browser View Transitions API circular ripple. -
Plus Jakarta Sans for UI legibility, Newsreader for editorial hooks, and JetBrains Mono (
tabular-nums) strictly reserved for scores, counters, and keyboard shortcuts (J/Kto navigate cards,Enterfor details,Ato pre-fill,/to search). - I kept our mascot (Noir Webling) and the interactive dual-layer HTML5 Canvas spider web in the background, toned down into a subtle horology-inspired filigree with an elastic silk thread that connects to whichever job card you are inspecting.
Try it in 60 seconds
The entire project is MIT-licensed and runs locally on Linux, macOS, and Windows (Python 3.11+):
git clone https://github.com/manny-ruesch/remote-job-hunter.git
cd remote-job-hunter
pip install -e .
rjh init # 4 quick questions (creates your profile.yaml)
rjh doctor # verifies your sources, SQLite WAL database, and optional LLM key
rjh serve # opens the Command Center on http://127.0.0.1:5070
** GitHub Repository:** https://github.com/manny-ruesch/remote-job-hunter
I Need Your Feedback (Help Me Break v0.2!)
This is a v0.2 release, and I want to shape the roadmap around real usage rather than guessing in a vacuum.
If you have 3 minutes to test it out, I would love your honest feedback in the comments (or via a GitHub Issue):
-
Try
rjh initon your own job search (whether you are looking for Backend, DevOps, AI/Automation, Frontend, or even a non-tech role). Did the heuristic scorer rank offers the way you expected, or did noisy offers slip through? - Test the Zero-API-Key Manual Mode with your regular ChatGPT / Claude / Gemini chat. Was the copy-paste flow smooth, or is there friction I should remove?
- Test the 1-Page ATS CV Tailor on a real job offer. How did the generated PDF look with your profile?
-
Which job boards or regional sources are missing? Right now it ships with Greenhouse, Ashby, Lever, Welcome to the Jungle, Remotive, We Work Remotely, Jobicy, Adzuna, and Hacker News. Tell me which board you check every week and I will add a connector for it in
v0.3.
If you find this useful, a ⭐ on GitHub helps a ton, and every bug report or critique in the comments below goes straight into the next release!

Top comments (0)