JobsHunt is a local web app for organizing a job search around your own resume materials and LLM providers. A FastAPI server and React UI run on your computer. You add API credentials and model choices in config; the app never requires a hosted SaaS backend.
Typical flow: set a resume vault (directory or one file), capture a posting (URL or paste), then use the UI to draft, evaluate, refine, track applications in a pipeline, and export artifacts. Data stays under paths you control (YAML + JSON on disk).
Caution
This project is a work in progress. For security purposes, you should assume the current codebase contains vulnerabilities. Security enhancements, hardening, and bug fixes are ongoing. Run this software only in environments you trust.
- Evaluation (structured JSON) — Overall score 1.0–5.0, dimension rows 1–5 with short labels and rationales, narrative fields (role summary, vault match, gaps, interview prep, story candidates), and a machine suggestion
apply/maybe/skipplus rationale. Output quality depends on your materials, the posting text, and the model. - Drafting — Tailored draft from vault or optional vault summary plus job spec; optional ATS-style refine (rules + full-document LLM passes).
- Fit & editing — Insights (heuristics ± LLM), apply selected insight lines, copilot chat with workspace context.
- Exports — TXT always; PDF/DOCX with optional
exportinstall (pip install -e ".[export]"). - Pipeline — Per-workspace rows (company, title, URL, status, scores, notes, run links).
- Story bank — STAR-style pins; optional bounded use inside drafts.
- Batch — Queue several jobs (server cap, commonly 15); items run one after another in a background job with polling.
- Scout (optional) — Playwright visits URLs you list in YAML; collects links whose paths look like job postings (heuristic keywords such as
/jobs/, and some ATS hostnames). Not a full ATS integration. - Outreach — Template + LLM personalization; copy only from the UI.
- Workspaces — Separate summary, pipeline, batch, runs, and story bank per workspace.
Configuration paths and secrets belong in your machine only — see Configuration. Do not commit real config.yaml or keys; the repo ships config.example.yaml only.
Outputs are suggestions: AI-generated content can be inaccurate. Review every draft, evaluation, and recommendation before applying or sending materials to employers.
No Auto-Submission: The app does not submit applications for you. It is designed for manual oversight.
Apply-Helper Scripts: While an optional local apply-helper script exists, it is disabled by default. Do not enable or run any helper scripts unless you have audited the code and trust the execution environment.
Data Privacy: While JobsHunt is local-first, it communicates with third-party LLM providers via API. Ensure you are comfortable with the privacy policy of the providers you configure in your AI settings.
Configure saved profiles and agent routing in the UI (/settings/ai). The JobsHunt agent uses a primary profile and optional fallbacks. Features such as draft, evaluation, vault-summary merge, refine, insights, copilot, and negotiate all call your provider through the same local stack; no third-party “app cloud” is required beyond the APIs you choose.
Early runs can be vague if the vault or preferences are thin. Add solid resume text, preferences / archetype hints, maintain an optional vault summary, and pin stories as you go. Large language models can still be wrong about facts — check employers, titles, and requirements yourself.
| Area | Status | Notes |
|---|---|---|
| Vault (folder/file, limits, native pickers) | Stable | PDF/DOCX inputs need export extra. Native pickers on macOS and Windows; on Linux edit paths or YAML. |
| Vault summary | Stable | Optional; can block draft when manifest is stale. |
| Draft / compose | Stable | Vault or summary + job spec. |
| Insights + apply insight items | Stable | Sanitizes common paste noise from terminals. |
| Refine for ATS | Stable | Optional auto_refine_after_draft. |
| Copilot chat | Stable | Workspace-scoped; UI can confirm or auto-apply model actions. |
| Structured evaluation | Stable | Schema v1; config can weight dimensions. |
| Pipeline | Stable | JSON per workspace. |
| Story bank | Stable | Optional in draft. |
| Batch draft | Stable | Sequential worker; ~15 item cap. |
| Export TXT / PDF / DOCX | Stable | PDF/DOCX need export extra. |
| AI settings | Stable | Profiles + jobshunt agent bindings. |
| Scout | Experimental | scout extra + Playwright; opt-in; obey site rules. |
| Apply-helper subprocess | Optional / advanced | Gated in config; security-sensitive. |
| Multi-workspace | Stable | Registry + directories per workspace. |
| Multi-user / SSO / cloud sync | Out of scope | Single-user local design. |
| Auto-submit to employers | Out of scope | Manual copy or your own script only. |
- Overview
- Responsible use
- LLM setup in this app
- Getting useful results
- Maturity
- Requirements
- Install prerequisites (macOS, Linux, Windows)
- Install JobsHunt
- GitHub Releases (desktop installers)
- Build the web UI
- Configuration
- Run
- First-time AI setup
- Feature reference (detailed)
- CLI reference
- Development
- Architecture
- Troubleshooting
- Git repository
- License
| Tool | Version | Role |
|---|---|---|
| Python | 3.9+ | Backend API, CLI (jobshunt) |
| Node.js | 18+ (LTS recommended) | Build the React UI (npm run build) |
| npm | Bundled with Node | UI dependencies |
Optional
| Tool | Role |
|---|---|
| Git | Clone and update the repository |
Playwright (via scout extra) |
Experimental portal scout in a real browser |
- Python 3.9+
- python.org macOS installer, or Homebrew:
brew install python@3.12 - Verify:
python3 --version
- python.org macOS installer, or Homebrew:
- Node.js 18+
- nodejs.org LTS, or Homebrew:
brew install node - Verify:
node --version,npm --version
- nodejs.org LTS, or Homebrew:
- Python 3.9+
- Example:
sudo apt update && sudo apt install python3 python3-venv python3-pip - Verify:
python3 --version
- Example:
- Node.js 18+
- Use NodeSource, nvm, fnm, or a distro package only if it provides Node ≥ 18.
- Verify:
node --version,npm --version
- Python:
sudo dnf install python3(or your distro’s Python 3.9+ package). - Node: Install Node 18+ via nvm, NodeSource, or equivalent if the default
nodejsis too old.
- Python 3.9+
- python.org Windows installer — check “Add python.exe to PATH”, or:
winget install Python.Python.3.12- Verify in PowerShell or Command Prompt:
py -3 --versionorpython --version
- Node.js 18+
- nodejs.org LTS Windows installer
- Verify:
node --version,npm --version
From the repository root (the folder that contains pyproject.toml):
Pre-built desktop installers are published on GitHub Releases. The marketing site and stable download links expect these exact filenames (attach them to each release, or CI will not match .../releases/latest/download/...):
| Asset | Description |
|---|---|
| JobsHunt-mac.dmg | macOS disk image (e.g. hdiutil create over packaging/pyinstaller/dist/JobsHunt.app after pyinstaller jobshunt.spec). |
| JobsHunt-Setup.exe | Windows installer produced by Inno Setup from packaging/windows/JobsHunt.iss (OutputBaseFilename=JobsHunt-Setup). |
If you ship a different layout temporarily (for example a .zip of the .app), rename consistently and update website/index.html to match.
App and installer icons are generated from packaging/icons/jobs-hunt-app.png (copy from website/assets/JobsHunt_Favicon.png when the mark changes); run packaging/icons/build_icons.sh (macOS; requires ImageMagick for multi-resolution .ico) to refresh JobsHunt.icns / JobsHunt.ico.
The installer detects your OS (Windows, macOS, or Linux), creates a .venv, installs [dev,export] with pip, builds the React UI only when src/jobshunt/static/ui/ is missing or you pass --rebuild-ui, then starts jobshunt serve by default. Missing Python 3.9+ (and Node 18+ when a UI build is required) can be installed automatically via winget, Homebrew, or apt/dnf where available; on errors it prints fix steps and lets you press Enter to retry (or use --non-interactive / env JOBSHUNT_INSTALL_NONINTERACTIVE=1 for CI).
Install and start the app (default — runs the server when install finishes):
macOS / Linux
./scripts/install.sh
# or: python3 install.pyWindows (PowerShell, from repo root)
.\scripts\install.ps1
# or: py -3 install.pyRelaunch only (after you close the browser or stop the server — skips pip/npm):
python3 install.py --serve-only
# Windows: py -3 install.py --serve-onlyInstall without starting the server (e.g. CI or scripting):
python3 install.py --install-onlyPass flags through to jobshunt serve after --, e.g. python3 install.py -- --port 8766. If that port is busy, jobshunt serve picks another free port and prints which one it chose.
Options: install.py --rebuild-ui, install.py --extras dev,export (default), install.py --venv .venv.
macOS / Linux
python3 -m venv .venv
source .venv/bin/activate
python -m pip install --upgrade pipWindows (PowerShell)
py -3 -m venv .venv
.\.venv\Scripts\Activate.ps1
python -m pip install --upgrade pipWindows (cmd)
py -3 -m venv .venv
.venv\Scripts\activate.bat
python -m pip install --upgrade pipCore + dev tests + resume export libraries (recommended):
pip install -e ".[dev,export]"export: adds ReportLab, python-docx, and pypdf so the app can read PDF/DOCX vault files and emit PDF/DOCX exports. Without it, some formats and export actions will tell you to install this extra.
Optional scout (Playwright)
pip install -e ".[scout]"
playwright install chromiumUse this only if you want the portal scout feature (browser automation). Respect each site’s terms and robots policies.
The FastAPI app serves the UI from src/jobshunt/static/ui/ after a production build.
From the repo root you can rebuild via python3 install.py --rebuild-ui (or py -3 install.py --rebuild-ui on Windows) instead of the manual npm steps below.
cd ui
npm ci
npm run build
cd ..If you do not yet have a lockfile workflow, npm install instead of npm ci is fine.
Released wheels include the built UI under jobshunt/static/ui/ (see python -m build after an ui build, and CI workflow .github/workflows/build-wheel.yml).
UI development (optional): from ui/, npm run dev starts Vite with a proxy to http://127.0.0.1:8765 — run jobshunt serve in another terminal so /api requests work.
| macOS / Linux (default) | Windows (default) | |
|---|---|---|
| Config | $XDG_CONFIG_HOME/jobshunt/config.yaml (often ~/.config/jobshunt/config.yaml) |
%APPDATA%\JobsHunt\config.yaml |
| Data | $XDG_DATA_HOME/jobshunt (often ~/.local/share/jobshunt) |
%LOCALAPPDATA%\JobsHunt\data |
Legacy paths (~/.config/jobhunt, ~/.local/share/jobhunt, %…%\JobHunt, JOBHUNT_HOME) are still used automatically when the newer jobshunt locations do not exist yet, so existing installs keep working without moving files.
Override both with environment variable JOBSHUNT_HOME (legacy JOBHUNT_HOME is also honored):
- Config:
$JOBSHUNT_HOME/config.yaml - Data:
$JOBSHUNT_HOME/data/
On Windows, set JOBSHUNT_HOME via System Properties → Environment Variables, or for a single session in PowerShell:
$env:JOBSHUNT_HOME = "C:\Users\You\jobshunt-data"-
Print the path the app will use:
jobshunt config-path
-
Copy
config.example.yamlto that path (same filenameconfig.yaml), then edit:jobshunt.resume_vault_path— folder of resumes or one resume file (.txt,.md,.docx,.pdfwith optional deps).jobshunt.output_path— optional explicit folder for exports; if empty, exports go under the app data tree (…/jobshunt/exportsor the legacy…/job_hunt/exportsif you still use an older data directory).http.host/http.port— bind address (default127.0.0.1:8765).
Never commit config.yaml if it contains API keys or personal paths (this repo’s .gitignore already ignores common cases).
jobshunt serveBy default the CLI opens a browser to the UI at http://127.0.0.1:8765/agents/jobshunt when using default host and port (your values may differ). If 8765 (or your configured port) is already in use, the server starts on another free port instead and prints which port it picked—use that URL if the first one does not load.
If you stopped the server or closed the terminal, start it again with python3 install.py --serve-only (from the repo root, with your venv already created) or activate .venv and run jobshunt serve.
If the UI was not built, visiting the root URL shows JSON with a hint to run cd ui && npm install && npm run build.
You can ship JobsHunt as a normal desktop app so users relaunch it from macOS Finder → Applications or Windows Start Menu / Program Files (no terminal).
Maintainers build a frozen bundle with PyInstaller, then:
- macOS: Drag
JobsHunt.appfrompackaging/pyinstaller/dist/into/Applications(or distribute a.dmgof that app). Data and config still use the usual~/Library/~/.configlocations (or%APPDATA%on Windows). - Windows: After running PyInstaller, open
packaging/windows/JobsHunt.issin Inno Setup and Compile to produce an installer that installs under Program Files and adds a Start Menu shortcut.
Quick path from repo root:
./packaging/build_desktop.shOr manually: build the UI (cd ui && npm ci && npm run build), install the project with extras (pip install -e ".[dev,export]" from the repo root), then cd packaging/pyinstaller && pyinstaller jobshunt.spec.
Details and prerequisites are in packaging/pyinstaller/jobshunt.spec. Optional: pip install -e ".[pack]" installs PyInstaller per pyproject.toml.
Code signing (macOS Gatekeeper / Windows SmartScreen) is not configured in-repo; for wide distribution you will need your own signing certificates.
JobsHunt calls your LLM through saved profiles (not the raw “form only”):
- Open AI settings in the UI (
/settings/ai). - Enter provider, Base URL, Model, optional API key, then save a row under My models (saved).
- Under JobsHunt model, choose Primary (and optional Fallbacks), then click Save agent routing.
Supported provider styles include OpenAI, Anthropic, Ollama, OpenAI-compatible proxies, and OpenRouter; path modes (/v1/chat/completions, responses-style paths, etc.) are configurable in the same screen.
Below is what the JobsHunt UI and API support at a high level. All REST routes are under /api/agents/jobshunt/ unless noted.
- Folder or single file: Config
resume_vault_pathcan point to a directory (multiple resumes) or one file. - Formats: Plain text / Markdown always; PDF and DOCX need
pip install -e ".[export]"(and libraries noted in error messages if missing). - Limits:
max_vault_charsandmax_vault_filesavoid sending huge vaults to the model (seeconfig.example.yaml). - Native folder/file pickers work on macOS and Windows (
pick-vault-folder,pick-vault-file,pick-output-folder). On Linux, type paths in settings or editconfig.yaml.
When use_vault_summary_for_context is enabled, the app can maintain a single condensed summary of the vault plus a manifest of incorporated files to save tokens and surface pending changes.
- Rescan — detect new/changed vault files vs manifest.
- Rebuild / merge — LLM-assisted update of the summary text.
block_draft_when_vault_summary_stale— can block drafting until pending files are merged (configurable).
Paths default under data/jobshunt/; vault_summary_path can override the summary file location.
- Job URL or pasted posting — Fetched or pasted content is normalized into a job spec for downstream steps.
- Draft / compose — Generates tailored resume text using vault (or vault summary) + job context.
- Insights — Heuristic ATS-oriented signals plus optional LLM commentary (skills, gaps, tips). Job paste text is scrubbed of common bracketed-paste terminal noise before use.
- Refine for ATS —
POST /api/agents/jobshunt/refine-resumeruns up to several heuristic → LLM full-resume revise rounds to clear non-good signals (line length, section headers, ASCII noise, etc.). Optionaljobshunt.auto_refine_after_draftruns this automatically after each draft (extra LLM cost). - Apply insight items —
POST /api/agents/jobshunt/apply-insight-itemsmerges selected gaps / quick wins into the current draft (one target section or per-item placement). - JobsHunt copilot —
POST /api/agents/jobshunt/chatwithworkspace_id: workspace-aware assistant that returns assistant_markdown plus optional client_actions (set_resume_text,set_job_paste,navigate_tab) and can execute refine / apply on the server when the model emits the corresponding actions. - Evaluation — Structured evaluation: dimensions, scores, role summary, match narrative, gaps, interview prep hints, story candidates, and a recommendation bucket — returned as structured JSON the UI renders.
- CRUD for pipeline rows: company, title, job URL, status (
new,evaluated,drafted,exported,applied,rejected,archived), notes, scores, links to run IDs, etc. - Stored locally per workspace under
data/jobshunt/workspaces/<workspace_id>/pipeline.json(see Workspaces).
- Pin structured “stories” (STAR-style) derived from evaluations or edits.
- Optional inclusion in drafts when
use_story_bank_in_draftis on.
- Templates and LLM-personalized variants for recruiter or follow-up messages (copy from UI; no auto-send).
- Queue multiple applications (cap enforced server-side, e.g. max 15) for draft generation; poll job status by
job_id.
- When
scout_enabledandscoutextra + Playwright browsers are installed, POST/scoutcan drive a browser session for supported flows. - Use responsibly and in line with site policies.
- POST
/exportproduces run artifacts (e.g. Markdown/Text; PDF/DOCX withexportextra) under the configured output / run layout. - GET
/runsand GET/download/{run_id}/{filename}list and download prior run files.
apply_helper_scriptplusallow_apply_subprocesscan run a user-defined helper (e.g. open a URL or a local tool). This is off by default; only enable scripts you trust.
- GET/PUT
/api/settings/ai— LLM profiles, API keys (stored locally in YAML), headers, temperature, token limits, OpenAI path vs gateway URL modes. - Per–JobsHunt routing — Primary/fallback profile IDs for the
jobshuntagent only.
- GET
/api/health— Liveness and version JSON.
| Command | Description |
|---|---|
jobshunt serve |
Start the API + static UI (opens browser). Options: --host, --port override config. |
jobshunt config-path |
Print resolved config.yaml path. |
jobshunt data-path |
Print resolved data root directory. |
jobshunt --version |
Show version. |
pip install -e ".[dev,export]"
pytestOptional linting: ruff is included in dev.
See ARCHITECTURE.md for package layout, routers, and data flow.
jobshunt: command not found— Activate your virtual environment and runpip install -e .again. With the venv active, thejobshuntconsole script should be on PATH (Scriptson Windows). If not, invoke the installed script by full path, e.g..venv/Scripts/jobshunt.exeon Windows or.venv/bin/jobshunton Unix.- Blank or JSON homepage — Run
npm run buildinui/sosrc/jobshunt/static/ui/exists. - 404 on
/agents/...after refresh — Ensure you are on a recent build ofjobshunt.app(SPA fallback servesindex.htmlfor client routes). - “Reading .pdf / .docx needs …” — Install
export:pip install -e ".[export]". - Scout errors — Install
scoutand runplaywright install chromium. - 400 / “No primary saved model” — Complete First-time AI setup: saved profile + Save agent routing.
- Port in use — Change
http.portinconfig.yamlor passjobshunt serve --port ….
If this folder is not yet a Git repo, from the project root:
git init
git add -A
git commit -m "Initial commit: JobsHunt local app".gitignore excludes virtualenvs, node_modules, local config.yaml, and generated *.egg-info/ — only commit config.example.yaml, not secrets.
MIT — see LICENSE.