Skip to content

About

Site-agnostic job-portal monitor with pluggable adapters and instant Telegram alerts.

Resources

Code of conduct

Contributing

Security policy

Stars

1 star

Watchers

0 watching

Forks

Latest commit

Β 

History

272 Commits

Folders and files

NameName
Last commit message
Last commit date
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Job Sentinel logo

Job Sentinel

Local-first career platform: multi-source job search, AI profile↔job match, application tracker, and ATS-tuned rΓ©sumΓ© generation, all on your own hardware.

CI OpenSSF Best Practices OpenSSF Scorecard Python 3.11+ License: MIT Ruff uv Conventional Commits

🌐 Live demo Β· πŸ“š Docs Β· πŸ“¦ Releases

Job Sentinel landing page with a live terminal replay of a real session: session check, scrape, AI resume build

Job Sentinel watches your university job portals, aggregates listings from public job APIs, tracks your applications, and generates ATS-ready rΓ©sumΓ©s and cover letters tailored to each role, entirely on your own machine. No API keys required for the defaults, no data leaving your hardware.

It ships with adapters for UTD 12twenty and Handshake, four no-key job sources (RemoteOK, The Muse, Arbeitnow, Himalayas), two opt-in keyed sources (Adzuna, USAJobs), company-board fetchers (Greenhouse/Lever/Ashby), and a multi-provider LLM layer you can point at Ollama, OpenRouter, Groq, Gemini, or OpenAI. Adding a new portal adapter takes one file and ~50 lines of Python.

🌐 Hosted demo vs. running locally: the live demo shows the interface, but the engine (scraping, local AI, PDF builds) runs on your machine by design: your portal credentials, your data, and the model never leave it. Follow the Quick Start below to run the real thing, about 5 minutes.

⚑ One-command setup

git clone https://github.com/harshitwandhare/job-sentinel && cd job-sentinel
bash scripts/install.sh        # macOS / Linux  (Windows: powershell -ExecutionPolicy Bypass -File scripts\install.ps1)
job-sentinel web               # API + web UI at http://localhost:3000

There's also a clip-to-track browser extension: one click on any job posting (LinkedIn, Greenhouse, Lever, Indeed…) drops it straight into your tracker.

πŸ“Έ What it looks like

Dashboard: pipeline, deadlines, source health Find jobs anywhere: multi-source search + filters
Dashboard Job search
Your profile is your rΓ©sumΓ©, rendered live, exports to ATS PDF Application tracker: saved β†’ applied β†’ offer
Profile rΓ©sumΓ© Applications
RΓ©sumΓ© studio: tailor + ATS score against any JD Settings: bring your own LLM (or local Ollama)
Studio Settings

Screens shown with the bundled demo dataset. Run locally for your real jobs, profile, and a private model.

🧭 Why this exists

The 2026 job market is brutal for students: the average opening now draws ~242 applications (3Γ— the 2021 volume), 93% of seekers have applied to a ghost job, and two-thirds have been rejected by an AI screen without a human ever reading their rΓ©sumΓ©. The edge that's left: apply early (watch portals, don't scroll them) and apply matched (ATS-clean documents tailored to each posting).

Every mainstream tool that helps with this is cloud SaaS, so your rΓ©sumΓ©, your application history, and the jobs you're chasing live on someone else's servers, behind a freemium meter. Job Sentinel is the same loop with the opposite architecture:

Job Sentinel Cloud trackers (Simplify/Teal/Huntr) AI auto-apply bots OSS resume builders
Open source βœ… MIT ❌ partly βœ…
Data stays on your machine βœ… by design ❌ ❌ cloud LLM keys ❌ usually
Portal monitoring + alerts βœ… ❌ ❌ ❌
Multi-source job search βœ… 7+ sources ❌ or limited ❌ ❌
Application tracker βœ… full CRUD βœ… cloud ❌ ❌
AI profile↔job match βœ… local + BYO βœ… cloud βœ… cloud ❌
Tailored ATS documents βœ… local LLM βœ… cloud βœ… cloud βœ… cloud
Account-ban risk none: you apply none high (ToS) none
Cost $0 forever freemium API costs $0 + API keys

One integrated pipeline, watch β†’ alert β†’ track β†’ tailor β†’ apply: typed, tested, and free, on hardware you already own.

Table of contents

✨ Features

Feature Details
Pluggable portal adapters One Python file per portal: no core changes needed
Multi-source job search Aggregate across RemoteOK, The Muse, Arbeitnow, Himalayas (no key); Adzuna, USAJobs (opt-in keyed); JobSpy scraper; Greenhouse/Lever/Ashby company boards
AI profile↔job match Blended ATS keyword + semantic embedding + optional LLM rationale; POST /api/match
Application tracker Kanban-style pipeline (saved β†’ applied β†’ interviewing β†’ offer/rejected); full CRUD via CLI, API, and web
Document library Generated rΓ©sumΓ©s and cover letters persisted with ATS scores; browse, download, or delete from the UI
Dashboard At-a-glance funnel stats, recent activity, and quick-action cards
Telegram bot Rich alerts + commands (/jobs, /applied, /stats, /deadlines, …)
RΓ©sumΓ© engine Universal profile β†’ ATS-friendly LaTeX/PDF, tailored per posting
BYO-LLM providers Ollama (local, default), OpenAI, OpenRouter, Groq, Gemini, or any custom OpenAI-compatible endpoint: swap per .env or the Settings page
Web UI Next.js + Tailwind app: dashboard, job search, applications, résumé library, settings, profile editor, studio, jobs board, chat, ⌘K palette
Hosted demo mode NEXT_PUBLIC_DEMO=1: every screen alive with realistic sample data; no backend needed
One-command web app job-sentinel web starts FastAPI + Next.js together
Local API FastAPI layer (job-sentinel serve) the UI consumes: one source of truth
Email + Telegram alerts Two notifier channels; email is optional SMTP
Deadline awareness /deadlines flags postings closing within a configurable window
Status tracking NEW β†’ SEEN β†’ APPLIED / IGNORED / CLOSED, persisted in SQLite
Closed detection Marks postings that disappear from the portal
Resume PDF import Upload an existing resume β†’ structured profile draft (local-LLM or heuristic)
Session management job-sentinel session validity check; login prefills credentials from .env
Per-job documents One-click tailored rΓ©sumΓ© + cover letter PDFs from any tracked posting
Optional auth AUTH_MODE=demo|required: PBKDF2 accounts, HMAC tokens, admin-managed invites
Production-grade mypy --strict, 450+ tests (80% gate), ESLint+vitest, OpenSSF Scorecard, reproducible uv.lock builds, Docker

πŸ— Architecture

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                             Job Sentinel                                β”‚
β”‚                                                                         β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”‚
β”‚  β”‚   Scheduler  │──▢│  SiteAdapter  │──▢│     JobRepository        β”‚   β”‚
β”‚  β”‚ (APScheduler)β”‚   β”‚  (Playwright) β”‚   β”‚  (sqlite-utils, SQLite)  β”‚   β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”˜   β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β”‚  job_postings            β”‚   β”‚
β”‚         β”‚                               β”‚  applications            β”‚   β”‚
β”‚         β–Ό                               β”‚  generated_documents     β”‚   β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”                       β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β”‚
β”‚  β”‚  Notifiers   β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚
β”‚  β”‚ Telegram/    β”‚  β”‚              FastAPI (local API)               β”‚  β”‚
β”‚  β”‚ Email        β”‚  β”‚  profile Β· jobs Β· match Β· applications Β·       β”‚  β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚  documents Β· sources Β· llm/config Β· ops        β”‚  β”‚
β”‚                    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”                   β”‚                                  β”‚
β”‚  β”‚ Job Sources  β”‚                   β–Ό                                  β”‚
β”‚  β”‚ (HTTP/JSON)  β”‚   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚
β”‚  β”‚ RemoteOK     β”‚   β”‚         Next.js Web UI (localhost:3000)      β”‚  β”‚
β”‚  β”‚ The Muse     β”‚   β”‚  dashboard Β· search Β· applications Β· resumes β”‚  β”‚
β”‚  β”‚ Arbeitnow    β”‚   β”‚  settings Β· jobs Β· profile Β· studio Β· chat   β”‚  β”‚
β”‚  β”‚ Himalayas    β”‚   β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚
β”‚  β”‚ Adzuna …     β”‚                                                      β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚
β”‚                     β”‚     LLM Provider Layer (documents/providers)  β”‚  β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”‚  OllamaBackend Β· OpenAICompatClient           β”‚  β”‚
β”‚  β”‚ Company ATS  β”‚   β”‚  (OpenAI / OpenRouter / Groq / Gemini /      β”‚  β”‚
β”‚  β”‚ Greenhouse   β”‚   β”‚   custom) Β· build_chat_backend/embed_backend  β”‚  β”‚
β”‚  β”‚ Lever Β· Ashbyβ”‚   β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜                                                      β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

See docs/design/HLD.md for the full High-Level Design and docs/design/LLD.md for Low-Level Design.


πŸš€ Quick Start

1. Prerequisites

  • Python 3.11+
  • uv (install: curl -LsSf https://astral.sh/uv/install.sh | sh)
  • A Telegram account

2. Clone & Install

git clone https://github.com/harshitwandhare/job-sentinel.git
cd job-sentinel

# Install all dependencies (creates .venv automatically)
uv sync

# Install Playwright's Chromium browser
uv run playwright install chromium

3. Create your Telegram bot

  1. Open Telegram and message @BotFather
  2. Send /newbot and follow the prompts β†’ copy the token
  3. Message your new bot once, then visit: https://api.telegram.org/bot<TOKEN>/getUpdates
  4. Copy your chat ID from the JSON response (message.chat.id)

4. Configure

cp .env.example .env
# Edit .env and fill in:
#   TELEGRAM_BOT_TOKEN=...
#   TELEGRAM_CHAT_ID=...
#   PORTAL_USERNAME=your_utd_netid
#   PORTAL_PASSWORD=your_password

5. Sign in once (Cloudflare-gated portals)

uv run job-sentinel login     # a browser opens; credentials prefill from .env,
                              # clear the challenge, click Sign In, done
uv run job-sentinel session   # verify: "βœ“ Session valid as <your name>"

⚠️ Don't add a viewId=<n> parameter to PORTAL_JOBS_URL: saved-search views can be "not authorized" for your account, which silently renders an empty list (the classic "scrape found 0 jobs" trap).

6. Test run (dry run: no messages sent)

uv run job-sentinel scrape

7. Start the full bot

uv run job-sentinel run

That's it. Open Telegram and send /start to your bot.


βš™οΈ Configuration

All configuration is via environment variables in .env. See .env.example for the full reference.

Variable Default Description
TELEGRAM_BOT_TOKEN (none) Required. From @BotFather
TELEGRAM_CHAT_ID (none) Required. Your Telegram user/chat ID
PORTAL_USERNAME (none) Required. Portal login
PORTAL_PASSWORD (none) Required. Portal password
PORTAL_JOBS_URL UTD 12twenty URL Full URL to the listings page
SITE_ADAPTER 12twenty Adapter to use
POLL_INTERVAL_SECONDS 900 Scrape interval (min: 60)
KEYWORD_FILTERS (empty = all) CSV: software,engineer,research
HEADLESS true Run browser headless
DRY_RUN false Scrape but don't send alerts
OLLAMA_MODEL llama3.2:3b Local model for AI features (3B fits 4 GB GPUs)
AUTH_MODE off off / demo (gate writes) / required (gate all)
LOG_LEVEL INFO DEBUG/INFO/WARNING/ERROR

πŸ€– Bot Commands

Command Description
/jobs Trigger a fresh scrape + show recent postings
/recent Show last 10 jobs from the database
/applied <id> Mark posting as applied
/ignore <id> Dismiss a posting
/status <id> Full details of a specific posting
/stats Counts by status (new / seen / applied / ignored / closed)
/deadlines Postings closing within DEADLINE_ALERT_DAYS
/filters Show active keyword filters
/adapters List available site adapters
/ping Health check

πŸ“„ RΓ©sumΓ© Generator

Job Sentinel keeps a universal profile: your master CV data in one hand-editable YAML file, and renders ATS-friendly PDFs from it. It's standalone: you don't need the Telegram bot configured to use it.

# 1. Scaffold a profile you can edit like an Overleaf source
uv run job-sentinel resume init        # writes data/profile.yaml

# 2. Edit data/profile.yaml: add education, experience, projects, skills…

# 3. Build an ATS-friendly PDF (also writes the .tex next to it)
uv run job-sentinel resume build -o data/resume.pdf
uv run job-sentinel resume show        # summarise your profile

# 4. Tailor to a specific posting: reorders content by relevance and
#    reports ATS keyword coverage (matched vs missing terms)
uv run job-sentinel resume build --job-text "paste a job description here"
uv run job-sentinel resume build --job-id <posting_id>   # a posting already scraped

# 5. Generate a tailored cover letter (deterministic, or --ai to polish locally)
uv run job-sentinel resume cover --job-text "…" --role "Student Assistant" --company "UTD"

PDF rendering uses Tectonic (a self-contained LaTeX engine, no full TeX install needed). Install it once:

winget install TectonicProject.Tectonic   # Windows
brew install tectonic                      # macOS
cargo install tectonic                     # Linux (or your package manager)

If Tectonic isn't installed, resume build still writes the .tex so you can compile it on Overleaf. The template is single-column with standard fonts and real selectable text, so it parses cleanly through ATS.

Optional: local-LLM rephrasing (no API key)

Add --ai to rephrase your bullets toward a posting using a local model via Ollama: fully offline, no API key, your data never leaves your machine. It only rephrases content already in your profile (it can't invent facts), and falls back to keyword tailoring if the model isn't available.

job-sentinel resume doctor --pull      # checks Ollama + pulls the model
job-sentinel resume build --ai --job-text "paste a job description"

AI providers (bring your own key)

Ollama is the zero-config default: no account, no key, fully offline. You can swap either the chat model or the embeddings model for any cloud provider (OpenRouter, Groq, Gemini, OpenAI) via the Settings page at http://localhost:3000/settings or by setting env vars in .env. Free tiers exist for OpenRouter, Groq, and Gemini. Groq is fast but does not support embeddings, so pair it with Gemini or Ollama for that slot.

See docs/llm-providers.md for the full reference: env var names, per-provider setup, graceful-degradation behaviour, and the privacy/security posture.


πŸ–₯ Web UI

Prefer a UI? Job Sentinel ships a local web app (Next.js + Tailwind) over a FastAPI layer: same engine, nicer surface. It's fully local: the API binds to localhost and the optional LLM stays on your machine.

# One command for everything: API + UI + recurring scrape watcher
uv run job-sentinel web --watch        # http://localhost:3000

# Or piecemeal:
job-sentinel serve                     # API only; Swagger at /docs
cd web && npm install && npm run dev   # UI only
Page URL What it does
Landing / Animated intro with a self-typing terminal session replay
Dashboard /dashboard Funnel stats, recent applications, and quick-action cards
Job Search /search Keyword search across enabled job sources; track results with one click
Applications /applications Kanban-style application pipeline (saved β†’ offer/rejected)
RΓ©sumΓ© Library /resumes Browse, download, and delete generated rΓ©sumΓ©s and cover letters
Settings /settings BYO-LLM provider config + job-source management; live test buttons
Profile /profile View and edit your universal profile (education, experience, projects…)
Profile Edit /profile/edit Full section editor + rΓ©sumΓ©-PDF import
Jobs Board /jobs Tracked portal postings; per-posting rΓ©sumΓ©/cover-letter generation
RΓ©sumΓ© Studio /studio Paste a JD β†’ live ATS coverage + AI match β†’ tailored PDF
Chat /chat Sentinel assistant: answers from your real data, local LLM for the rest
Login /login Auth gate (when AUTH_MODE=demo|required)

The ⌘K command palette (CommandPalette) is always available for fast navigation. Hosted-demo mode (NEXT_PUBLIC_DEMO=1) populates every screen with realistic sample data so visitors can explore without a running backend.

Jobs board: real scraped postings, one-click tailored documents RΓ©sumΓ© studio: paste a JD, get ATS coverage + a one-page PDF
Jobs board with scraper controls, session status, and per-posting resume/cover-letter buttons Resume studio with job-description input, ATS scoring, and local-AI toggle

Sharing your instance (optional auth)

Want a public demo of your instance, or to invite a friend? Turn on authentication, stdlib-only, no services:

job-sentinel users add yourname --admin   # first account must be an admin
AUTH_MODE=demo job-sentinel serve          # reads public, actions need login

AUTH_MODE=demo keeps browsing open but gates actions; required gates everything. Admins create further accounts (users add, or POST /api/auth/users). Details in docs/deployment.md.


πŸ”Œ Adding a New Portal

  1. Create src/job_sentinel/adapters/sites/my_portal.py
  2. Subclass SiteAdapter, implement login() and scrape_page()
  3. Set SITE_ADAPTER=my_portal in your .env

Full guide: docs/design/adapter-authoring.md


πŸ›  Development

# Install dev dependencies
uv sync --all-extras

# Install pre-commit hooks (runs ruff, mypy, secret scan on every commit)
uv run pre-commit install

# Run tests
uv run pytest

# Lint & format
uv run ruff check --fix .
uv run ruff format .

# Type check
uv run mypy src/

# All at once (same as CI)
uv run pre-commit run --all-files

🐳 Deployment (always-on) & data persistence

Run it continuously with Docker. The image is based on the official Playwright image (Chromium + system libs included):

docker compose up -d --build     # start detached
docker compose logs -f           # follow

Your data never vanishes on restart. ./data and ./logs are bind-mounted from the host, so the SQLite database, captured login session, and your profile live on disk, surviving container restarts, rebuilds, and reboots.

12twenty's login is Cloudflare-gated, so capture a session on the host first with job-sentinel login (it writes data/session.json, which the container mounts and reuses). Re-run login if the session expires.

Backups. Everything important is in data/. Back it up while the bot is idle, for example a WAL-safe SQLite copy:

sqlite3 data/jobs.db ".backup data/jobs.backup.db"
cp data/profile.yaml data/profile.backup.yaml

πŸ“ Project Structure

job-sentinel/
β”œβ”€β”€ src/job_sentinel/
β”‚   β”œβ”€β”€ adapters/              # Plugin system: base interface, registry,
β”‚   β”‚   └── sites/             #   12twenty + Handshake adapters
β”‚   β”œβ”€β”€ api/                   # FastAPI layer: routes, ops runner, auth, chat
β”‚   β”œβ”€β”€ bot/                   # Telegram command handlers
β”‚   β”œβ”€β”€ config/                # pydantic-settings config + loguru setup
β”‚   β”œβ”€β”€ core/                  # Browser, models (JobPosting/Application/
β”‚   β”‚                          #   GeneratedDocument), scheduler, session, text
β”‚   β”œβ”€β”€ db/                    # sqlite-utils repository (schema v2)
β”‚   β”œβ”€β”€ documents/             # Resume engine: LaTeX, tailoring, LLM,
β”‚   β”‚                          #   embeddings, cover letters, PDF import,
β”‚   β”‚                          #   providers (ChatBackend/EmbedBackend), match
β”‚   β”œβ”€β”€ notifiers/             # Telegram (MarkdownV2) + SMTP email
β”‚   β”œβ”€β”€ profile/               # Universal profile models + YAML store
β”‚   β”œβ”€β”€ sources/               # Pluggable job-source layer: JobSource ABC,
β”‚   β”‚                          #   registry, aggregate_search; RemoteOK / The Muse /
β”‚   β”‚                          #   Arbeitnow / Himalayas / Adzuna / USAJobs / JobSpy;
β”‚   β”‚                          #   company_boards (Greenhouse/Lever/Ashby)
β”‚   └── __main__.py            # Typer CLI entry-point
β”œβ”€β”€ web/                       # Next.js UI (App Router, Tailwind, vitest)
β”‚   β”œβ”€β”€ app/                   # page.tsx per route (landing, dashboard, search,
β”‚   β”‚                          #   applications, resumes, settings, jobs, profile,
β”‚   β”‚                          #   studio, chat, login)
β”‚   β”œβ”€β”€ components/            # AiMatch, DataTable, SearchResultCard, JobsExplorer,
β”‚   β”‚                          #   ResumePaper, CommandPalette, Nav, ScraperControls…
β”‚   └── lib/                   # api.ts (typed client), demo.ts (NEXT_PUBLIC_DEMO)
β”œβ”€β”€ tests/                     # unit/ Β· integration/ Β· e2e/ (450+ tests)
β”œβ”€β”€ docs/                      # MkDocs site: HLD, LLD, ADRs, llm-providers,
β”‚                              #   compliance, deployment, NORTH_STAR
β”œβ”€β”€ .github/workflows/         # CI Β· Release Β· Docs Β· Scorecard
β”œβ”€β”€ pyproject.toml             # Single source of truth (uv + hatchling)
└── uv.lock                    # Reproducible builds (CI uses --locked)

πŸ“‹ Roadmap

  • RΓ©sumΓ© engine (universal profile β†’ ATS LaTeX/PDF) with per-posting tailoring
  • Local-LLM rephrasing via Ollama (no API key)
  • Web UI (Next.js) + local FastAPI layer: full CLI feature parity
  • Email notifier (optional SMTP) alongside Telegram
  • Deadline-aware tracking (/deadlines)
  • Docker / docker-compose with persistent data
  • Cover-letter generation (deterministic + local-LLM polish)
  • Semantic relevance ranking (local embeddings via Ollama)
  • Resume PDF import β†’ structured profile draft
  • Session validity checks + credential-prefilled login
  • Optional multi-user auth (demo/required modes, admin invites)
  • Hosted demo (Vercel) + docs site (GitHub Pages): both $0
  • Multi-source job search: RemoteOK, The Muse, Arbeitnow, Himalayas, Adzuna, USAJobs, JobSpy; Greenhouse/Lever/Ashby company boards (see ADR 005)
  • BYO-LLM providers: OpenAI, OpenRouter, Groq, Gemini alongside Ollama; configurable from Settings UI (see docs/llm-providers.md)
  • AI profile↔job match: blended ATS + semantic + grounded LLM rationale (POST /api/match)
  • Application tracker: full CRUD pipeline (saved β†’ interviewing β†’ offer/rejected), CLI + API + web
  • Document library: persisted generated rΓ©sumΓ©s and cover letters with ATS scores
  • Dashboard: funnel stats, recent activity, quick actions
  • ⌘K command palette
  • Deeper ATS scoring: parser-style simulation of the big enterprise ATSes, beyond keyword coverage
  • Ghost-job signals: flag stale/repost patterns before you sink hours in
  • Application analytics: funnel stats over your own history (response rates by employer, day-of-week, match score)
  • Discord webhook notifier
  • Playwright e2e suite against job-sentinel web
  • Packaged installers + PyPI publish

🀝 Contributing

Contributions are welcome! Please read CONTRIBUTING.md first.

All commits must follow Conventional Commits. Run uv run pre-commit install to enforce this automatically.


πŸ‘€ Author

Built and maintained by Harshit Wandhare: a CS student who got tired of the 2026 job grind and decided to engineer a way through it. If this project is useful, a ⭐ helps; if you're hiring, I'd love to talk.


πŸ“„ License

MIT Β© Harshit Wandhare: see LICENSE.

About

Site-agnostic job-portal monitor with pluggable adapters and instant Telegram alerts.

Resources

Code of conduct

Contributing

Security policy

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages