A private, open-source desktop job-hunting assistant that runs entirely on your machine.
Huntly discovers relevant vacancies from sources you choose, ranks them against your professional profile, generates tailored CVs and cover letters from facts you entered, and prepares application emails as Gmail drafts that you must explicitly approve before anything is sent. A daily digest lands in your own inbox.
- Local-first. A native desktop window (Tauri) talking to a local Python core over
127.0.0.1. Your data lives in one folder on your computer. - Bring your own keys. Google OAuth client, X API bearer token and Groq API key are entered by you during onboarding and encrypted at rest (AES-256-GCM, Argon2id). The maintainers have no server, no copy of your keys and no way to decrypt them.
- No telemetry. No analytics, crash reporting, update pings or remote logging.
- Approval gate. Application emails are hashed when you approve them; any edit invalidates the approval, approvals expire, and background jobs have no code path to send.
- Never invents content. CVs and letters are assembled only from your profile. Optional AI wording is discarded automatically if it mentions anything that is not in your profile.
Licensed under Apache-2.0.
- Features
- Install (Linux / Kali)
- First run
- Credentials you may need
- Job sources
- Development
- Architecture · Local API · Security
| Screen | What it does |
|---|---|
| Today | A one-line briefing, your pipeline at a glance, strongest leads, and a "Needs you" list (emails to approve, follow-ups due, failing sources, profile gaps). |
| Discover | Keyboard triage (J/K move, S shortlist, D dismiss, A apply, O open). Every job shows a heat meter and an explainable score breakdown. Prompt-injection attempts in postings are flagged. |
| Applications | A board by stage. Each application walks you through making an ATS-friendly CV and cover letter, writing the email, and approving it, with an ATS readiness report and notes. |
| Approvals | The email exactly as the recipient will see it, a checklist you tick before approving, time-limited approval, Gmail drafts, reply status and follow-ups. |
| Profile | Import your existing CV (PDF/Word, parsed locally), then edit every section: contact details including LinkedIn, GitHub and website, experience, education, projects and preferences. Plus your file library. |
| Sources | RSS/Atom, Greenhouse, Lever, Remotive, Arbeitnow, company career pages (schema.org JobPosting), X recent search. Health, last run and errors per source. |
| Insights | Found vs applied over time, match distribution, where applications stand, jobs per source, demand for your skills. |
| Settings | Search interval, digest time (Africa/Lagos), reply tracking and follow-up timing, AI options, approval expiry, accounts and keys, vault, privacy, activity log. |
The window has a native menu bar (File / Edit / Go / Help with keyboard shortcuts) and a system-tray icon (show, search now, quit). Global search: Ctrl+K.
- Import: upload the CV you already have. Huntly extracts the text on your computer (pypdf / python-docx) and maps it to profile fields with rules, so every value comes from your document. You review each field before anything is saved.
- Tailor: for each job, skills and achievements the posting asks for move to the top. With Groq enabled, the summary and cover letter can be reworded for the job; any AI wording that mentions something not in your profile is discarded automatically.
- ATS-friendly: one column, no tables, images or text boxes, standard headings (Summary, Skills, Work Experience, Education), contact details and LinkedIn as plain text, real selectable text, PDF metadata and a file name with your name in it.
- ATS report: how many of the job's keywords your CV covers, which ones you're missing (shown, never added for you), and a format checklist.
Huntly does not track whether emails were opened. That requires a tracking image served from a public server, which a local app doesn't have; it is also unreliable (mail clients pre-load images) and hurts deliverability. Instead:
- Reply tracking: every two hours Huntly reads the sender headers of the Gmail threads
your applications started (
gmail.metadatascope; message bodies are never read) and tells you when an employer replies, so you can update the stage. - Reply sorting (optional, off by default): turn on "Read replies to sort them" and Huntly
also opens replies in your application threads (needs
gmail.readonly) and checks them on your computer for interview, rejection or offer wording, then suggests the stage. The reply text is never stored or sent anywhere, and you always confirm the stage yourself. - Follow-ups: after a configurable number of days with no reply (default 7), Huntly suggests a short follow-up in the same thread. It goes through the same approval gate as every other email. At most two follow-ups per application.
Download the file for your system from the latest release and check it against the SHA-256 shown on the release page.
Linux (Debian, Ubuntu, Kali)
sudo apt install ./Huntly_0.1.1_amd64.debOr, on any distribution, make the AppImage executable and run it:
chmod +x Huntly_0.1.1_amd64.AppImage && ./Huntly_0.1.1_amd64.AppImage.
macOS (aarch64 for Apple silicon, x64 for Intel): open the .dmg and drag Huntly to
Applications. The app is not code-signed yet, so the first time, right-click it and choose
Open, or run xattr -dr com.apple.quarantine /Applications/Huntly.app.
Windows: run Huntly_0.1.1_x64-setup.exe. It is not code-signed yet, so SmartScreen may
warn you: choose More info → Run anyway.
Requirements: Python ≥ 3.11, Node.js ≥ 20, Rust ≥ 1.77 and the Tauri system libraries:
sudo apt install -y libwebkit2gtk-4.1-dev libgtk-3-dev libsoup-3.0-dev librsvg2-dev \
libayatana-appindicator3-dev build-essential libssl-dev patchelf file
git clone https://github.com/Kingvic300/Huntly.git huntly && cd huntly
scripts/setup-dev.sh # Python venv + npm packages
scripts/test.sh # all automated tests
scripts/build-linux.sh # produces release/*.deb and release/*.AppImagescripts/build-linux.sh first freezes the Python core into a single executable with
PyInstaller and bundles it inside the Tauri package as a sidecar, so the installed app
needs no Python.
macOS and Windows installers are built by GitHub Actions (.github/workflows/release.yml)
on each platform whenever a v* tag is pushed. To build one yourself on that platform, run
scripts/build-sidecar.sh and then npx tauri build in desktop/.
- Welcome explains the local-only, open-source model and shows where data is stored
(
~/.local/share/huntlyon Linux). - Master password creates your encrypted vault. Optionally let the OS keychain (libsecret / GNOME Keyring / KWallet) unlock it automatically on this device.
- Your API keys — add any of the credentials below. Each is encrypted before it is written to disk.
- Gmail — opens Google's consent screen in your browser using your OAuth client.
- Profile — basics now; the full editor lives in CV Library.
Nothing in Huntly works against fake or sample data: until you add sources, the job list is empty, and until you connect Gmail, digests and sending are disabled.
All optional — enable only what you use.
| Credential | Used for | How to get it |
|---|---|---|
| Google OAuth client (Desktop app JSON) | Gmail drafts, approved sends, daily digest, reply tracking | Google Cloud Console → create project → enable Gmail API → Google Auth Platform (OAuth consent screen): External, then Audience → Test users → add your own Gmail address → Credentials → OAuth client ID → Desktop app → download JSON. Recommended: on Audience click Publish app (no verification needed for personal use); in Testing mode Google expires the connection every 7 days. When connecting, Google warns the app is unverified; it is your own app, so choose Continue. If you see Error 403: access_denied, your address is not on the test-user list. Scopes requested: gmail.compose (drafts and sending) and gmail.metadata (message headers only, for reply tracking). Huntly cannot read email content. |
| X API bearer token | X recent-search source | developer.x.com → project/app → Bearer Token. Requires an access tier that includes GET /2/tweets/search/recent. |
| Groq API key | Optional AI fit notes and cover-letter wording | console.groq.com → API Keys. |
| Type | Endpoint | Notes |
|---|---|---|
| RSS / Atom | any feed URL | Many boards publish feeds. |
| Greenhouse | boards-api.greenhouse.io/v1/boards/{board}/jobs |
Public Job Board API. |
| Lever | api.lever.co/v0/postings/{company} |
Public Postings API. |
| Remotive | remotive.com/api/remote-jobs |
Public API; links back to Remotive as required. |
| Arbeitnow | arbeitnow.com/api/job-board-api |
Public API. |
| Career page | any URL | Reads only schema.org JobPosting JSON-LD the site publishes. No scraping, no JS. |
| X recent search | api.x.com/2/tweets/search/recent |
Your bearer token; retweets excluded. |
All fetches go through an SSRF guard (http/https only, public addresses only, re-checked on every redirect, size and time limits). Respect each site's terms of service.
scripts/setup-dev.sh
scripts/dev.sh # tauri dev: Vite on :1420 + native window; core spawned from .venvRun the core alone: HUNTLY_API_TOKEN=dev .venv/bin/python -m huntly --port 8765
(set HUNTLY_DATA_DIR to use a throwaway data folder).
Repository layout:
core/ Python core (FastAPI, SQLAlchemy, Alembic, APScheduler)
huntly/ application package
tests/ pytest suite (all external services mocked)
packaging/ PyInstaller spec for the sidecar
desktop/ Tauri shell (Rust) + React/TypeScript/Tailwind UI
scripts/ setup, dev, test and build scripts
docs/ architecture and API reference
See CONTRIBUTING.md. Report vulnerabilities privately as described in SECURITY.md.
docker-compose.yml runs only the headless core (no UI) for people who want to script
against the local API. It binds to 127.0.0.1 on the host and needs HUNTLY_API_TOKEN.
The desktop app does not need Docker.