Skip to content

Latest commit

 

History

8 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Velto

Velto is a personal, local job application agent (Tsenta-style). Runs on your machine: monitor company boards, score fit, tailor résumés, auto-apply where possible, and track outcomes — without a hosted SaaS.

Stack: FastAPI · SQLite · Playwright · React · Vite · Tailwind · Ollama (or Gemini / rules)


What it does

Area Capabilities
Profile Upload résumé (PDF/DOCX) — auto-fills name, contact, skills, target titles; automation toggles
Jobs Paste URLs (Greenhouse, Lever, Ashby, Workday, gh_jid= links); match %, tailor, apply
Monitoring 24/7 watchlist scans (tiered intervals), CSV import, scan logs, manual scan, repair boards
Applications Status pipeline, error messages, apply receipts & screenshots
Inbox IMAP sync, classify mail (confirmation / interview / rejection / offer), link to jobs
Dashboard Open roles, match pipeline, applications, inbox stats, AI health

Board monitoring (Tsenta-style)

  • Polls Greenhouse, Lever, and Ashby job boards on a schedule (tier A ≈ 15 min, B ≈ 60 min, C ≈ 6 h).
  • Adds new postings when they appear on a board.
  • Closes roles that disappear from a board (PRUNE_CLOSED_JOBS, default on) — list stays fresh even when nothing new is posted.
  • Re-opens a role if it returns to the board later.
  • Skips closing jobs you are actively working (tailoring, ready, in-flight applications).

Match & apply

  • LLM providers: ollama (local, recommended) · gemini · rules (instant keywords, no AI).
  • Monitor scans use fast rule-based matching by default (MONITOR_RULES_ONLY=true) so boards do not block on Ollama.
  • Tailoring: per-job résumé rewrite with diff view + cover letter (PDF export).
  • Auto-apply: Playwright (Greenhouse, Lever, Ashby, Workday best-effort). Set AUTO_APPLY_ENABLED=true only when you trust submit behavior.

UI

  • Dark / light mode (system default, toggle in sidebar).
  • Jobs list: newest first or best match, auto-refresh, show closed toggle, open vs closed counts.
  • Monitoring: live scan stats including closed (24h).

Requirements

  • Python 3.13
  • Node 18+
  • Ollama (recommended) or a Gemini API key
  • Playwright Chromium (for auto-apply):
cd backend && .venv/bin/playwright install chromium

Quick start

cp .env.example .env
# Edit .env — quote passwords: IMAP_PASSWORD="your app password"

# Ollama (recommended)
brew install ollama && ollama serve
chmod +x scripts/setup-ollama.sh && ./scripts/setup-ollama.sh

# Backend
cd backend
python3.13 -m venv .venv
.venv/bin/pip install -r requirements.txt -r requirements-dev.txt
.venv/bin/playwright install chromium

# Frontend
cd ../frontend && npm install

# Run from project root
cd ..
chmod +x scripts/dev.sh scripts/setup-playwright.sh
./scripts/dev.sh
Service URL
App http://localhost:5173
API http://127.0.0.1:8000
OpenAPI http://127.0.0.1:8000/docs

Health check:

curl http://127.0.0.1:8000/api/health

Typical workflow

  1. Profile — upload résumé, set skills & target titles; optional monitor auto-tailor / auto-apply toggles.
  2. MonitoringLoad starter watchlist or Import CSV (docs/watchlist_template.csv).
  3. Wait for scans (or Scan now on a source). New roles land under Jobs; removed board postings move to closed.
  4. Jobs — review matches, tailor, queue & apply. Paste one-off URLs (including Workday) here.
  5. Applications — track submitted, needs_you, failed; open screenshots when present.
  6. Inbox — set EMAIL_ENABLED=true and IMAP vars, then Sync inbox.

Environment variables

Variable Default Description
LLM_PROVIDER ollama ollama · gemini · rules
OLLAMA_BASE_URL http://127.0.0.1:11434 Ollama API
OLLAMA_MODEL llama3.2:3b Model for match/tailor
LLM_FAST_MODE true Shorter prompts in dev
GEMINI_API_KEY Required if LLM_PROVIDER=gemini
GEMINI_MODEL gemini-2.5-flash Primary Gemini model
AUTO_APPLY_ENABLED false Playwright clicks final submit
MATCH_THRESHOLD 60 Min score to treat as matched
MAX_APPS_PER_DAY 10 Daily submit cap
MONITOR_ENABLED true Background watchlist worker
MONITOR_TICK_SECONDS 60 How often due scans are checked
MONITOR_RULES_ONLY true Keyword match during board scans (no LLM per job)
PRUNE_CLOSED_JOBS true Mark jobs missing from latest board scan as closed
EMAIL_ENABLED false IMAP inbox sync
IMAP_HOST / IMAP_PORT / IMAP_USER / IMAP_PASSWORD / IMAP_FOLDER Gmail defaults Use App Password for Gmail
EMAIL_SYNC_LIMIT 50 Max messages per sync
CORS_ORIGINS localhost:5173 Frontend origins

Tip: Always quote values with spaces or special characters in .env, e.g. IMAP_PASSWORD="xxxx xxxx".


Watchlist CSV

company_name,ats_type,board_slug,tier
Stripe,greenhouse,stripe,A
Netflix,lever,netflix,C

Template: docs/watchlist_template.csv

  • Supported board types: greenhouse, lever, ashby
  • Workday is not board-monitored — paste myworkdayjobs.com URLs on the Jobs page

Jobs list behavior

  • API stores all jobs in SQLite; the UI lists up to 200 at a time (GET /api/jobs/count shows open vs closed totals).
  • Default sort: newest first; switch to best match on the Jobs page.
  • Closed roles (removed from boards) are hidden unless Show closed is on.
  • Recompute match % refreshes scores only — it does not fetch boards (monitoring does that).
  • If scans show 0 new but the list changes, pruning may have closed stale postings — check Monitoring scan logs.

Application statuses

Status Meaning
queued / tailoring / ready Pipeline in progress
needs_you Form prefilled; finish CAPTCHA, custom questions, or submit manually
submitted Playwright (or you) completed submit
failed Error recorded on the application
skipped Below threshold or skipped intentionally

Job status closed = role no longer on the company board (still in DB; visible with Show closed).


Tests

./scripts/test.sh

Covers watchlist CSV parsing, LLM JSON extraction, email classification, board ingest/dedupe, closed-job pruning, and reopen logic.


Project structure

job_applyer/
├── backend/
│   ├── app/
│   │   ├── routers/       # profile, jobs, applications, watchlist, inbox, dashboard
│   │   ├── services/      # matcher, tailor, apply, board_fetcher, board_prune, email_*
│   │   ├── workers/       # monitor (24/7 scans)
│   │   └── models/        # SQLAlchemy entities
│   ├── data/              # SQLite DB, résumés, receipts (gitignored)
│   └── tests/
├── frontend/              # React SPA
├── docs/
│   ├── watchlist_template.csv
│   └── AUDIT.md           # architecture & gap notes
└── scripts/
    ├── dev.sh             # start API + Vite (frees ports 8000/5173 on exit)
    ├── test.sh
    ├── setup-ollama.sh
    └── setup-playwright.sh

Security & scope

  • Built for single-user local use. There is no API authentication — keep the backend on 127.0.0.1 only.
  • Do not expose port 8000 to your LAN or the internet without adding auth.
  • .env is gitignored; never commit API keys or app passwords.

Known limitations

  • Workday forms vary widely; many runs end in needs_you.
  • Email → job linking is heuristic (company + title); use manual link in Inbox when wrong.
  • Large job DBs: list is capped at 200 rows; use filters/sort and closed pruning to keep the feed useful.
  • Ollama is local with no API quota; slowness usually means model load or CPU, not rate limits.

For a deeper review (gaps, fixes, roadmap), see docs/AUDIT.md.


Phase history (reference)

Phase Focus
1 Profile, job intake, match, tailor, apply, tracker, dashboard
2 24/7 watchlist, Lever/Ashby, automation pipeline, monitoring UI
3 CSV import, Workday adapter, IMAP inbox
Recent Closed-job pruning, jobs UX (sort/refresh/closed), light/dark UI, pytest suite, audit fixes

About

No description, website, or topics provided.

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages