Start here
Quickstart
Install, run the API and the dashboard, and turn on the schedule.
From a fresh clone to a running pipeline in about fifteen minutes. You need macOS, Python 3.12, Node 20+ and uv.
- Install the Python sideThe package is
jobhunter, pinned to Python 3.12.terminalgit clone https://github.com/Tejmul/Zonuly.git && cd Zonuly uv sync # or: python -m venv .venv && pip install -e . uv sync --extra research # optional: the web-research backends - Add your keysCopy the template and fill in what you have. Only
OPENROUTER_API_KEYis required to start; everything else switches a channel on. The file is git-ignored.See Environment variables for every name.terminalcp .env.example .env - Check the machine
doctorchecks the OpenRouter key and model aliases, today's budget, the parsed resume, GitHub, Hunter and Gmail — and says how to fix whatever is missing.terminalpython scripts/run.py doctor - Teach it your resumePut your resume at
profile/resume.pdfand parse it intoprofile/profile.json— the profile every score and every email is built from.terminalpython scripts/run.py profile - Start the APIFastAPI on
127.0.0.1:8000, with interactive API docs at/docs. It also starts an in-process scheduler (daily scrape at 08:00, reply check every hour).terminalpython scripts/run.py serve - Start the dashboardterminal
cd dashboard npm install npm run dev # http://localhost:3000 - Fill it once by handA first scrape and score so the dashboard has something to show.terminal
python scripts/run.py scrape python scripts/run.py score --limit 40 - Turn on the scheduleInstalls the background jobs as macOS LaunchAgents, so the pipeline keeps working without a terminal open.terminal
python scripts/run.py tick install python scripts/run.py tick status
What is now running#
| Job | When | Does |
|---|---|---|
| com.zonuly.tick.free | every 10 min | The free work: replies, people, addresses, fill, hiring proof, discovery |
| com.zonuly.tick.paid | 06:15 daily | The model work inside the OpenRouter budget |
| com.zonuly.tick.send | every 5 min | Sends at most one approved email whose slot is due |
| com.zonuly.apify | every 30 min | Referrals: LinkedIn People tabs for the shortlist, tech team only |
| com.zonuly.shortlist | every 10 min | Completes one shortlisted company at a time, Bengaluru first |
| com.zonuly.audit | hourly | Checks every field is still filling and every channel answers |
| com.zonuly.apify | every 30 min | Buys LinkedIn People tabs for companies short of referrers, inside the daily Apify cap |
Referrals are Apify's job
Since 23 Oct 2026 the free people-search job is off (tick.free_referral_job: false): referrals come from the Apify job, the shortlist first and the tech team only. To pause all scraping, set tick.scrapers_frozen: true. See Scheduling.Details in Scheduling & the tick.
Your first decision#
Once roles are scored, let the brain rank the companies and open Best bets: today's company is at the top. See The decision brain.
terminal
python scripts/run.py decide runBefore you send anything real
Sending starts in dry-run (emails written to outbox/). Connect Gmail in Settings → Email, run python scripts/run.py outreach preflight, and only then set outreach.send_mode: gmail. Keep the laptop awake and on power during the send window, 10:00–19:00.