Inspiration
Applying for jobs is death by a thousand tabs. You scrape listings in one place, rewrite your CV in another, paste applications into a spreadsheet, refresh your inbox waiting for a reply, then scramble to prep when an interview invite finally lands. Every step is manual, and the context, which job, which CV version, what stage, is scattered across tools that don't talk to each other. We wanted one place that treats the job hunt as a single pipeline: find the role, tailor for it, apply, track it, and prepare, with the busywork automated and a human always in control of the decisions that matter.
What it does
Athena AI follows the whole job hunt as one connected flow:
- Discover — scrape LinkedIn postings by title and location.
- Match — embed your resume and the jobs, rank them by relevance, and filter/re-rank against your stated preferences (salary, work mode, must-have skills, deal-breakers).
- Tailor — adapt your CV to a specific posting and keep versioned variants.
- Apply & track — maintain an application pipeline (scored → applied → interview → offer / rejected) that updates itself.
- Watch the inbox — a Gmail watcher reads job-related emails, classifies them (interview invite, rejection, offer…), and advances the matching application automatically — only when it's confident.
- Prepare — practise interviews by job title with structured scoring and post-session reports. The whole thing is driven from a single dashboard.
How we built it
- Frontend: a Next.js dashboard that unifies the jobs feed, application pipeline, CV editor, interview practice, and LinkedIn connection.
- Two FastAPI backends: a scraping/LinkedIn service (Playwright) and the "Athena" server for the email watcher, interviews, and profiles.
- LinkedIn login from the web: since a browser can't hand a site's session to another app, we run a real headful Chromium server-side on a virtual display (Xvfb) and stream it to the dashboard over VNC (x11vnc + noVNC) — the user logs in normally, 2FA and all, without ever pasting a cookie.
- Encrypted session persistence: the captured LinkedIn session is Fernet-encrypted and stored in Supabase, so it survives restarts and redeploys with no local file — and never touches the browser.
- Matching: Qwen3 embeddings (via vLLM) rank resume↔job by cosine similarity, plus an LLM that turns a free-text wishlist into structured preferences for filtering and re-ranking.
- Email automation as a deterministic pipeline: Groq + Instructor classify each email against strict intent definitions, RapidFuzz matches the company to an active application, and a fixed transition table applies a status change only when both signals are strong — everything else goes to human review.
- Data: Supabase (Postgres) is the shared datastore across all slices.
- Deploy: frontend on Vercel, scraper backend on Railway via Docker.
- Process: we worked in parallel slices with spec → plan → test-driven implementation → review, and integrated through Supabase and shared API contracts. ## Challenges we ran into
- You can't capture a LinkedIn session from a web app. Auth cookies are httpOnly and cross-origin, so the frontend simply can't read them. That forced the whole streamed-server-browser architecture (Xvfb + x11vnc + noVNC) — the hardest and most interesting part of the build.
- Keeping the session alive across restarts. Ephemeral containers meant a login vanished on every deploy. We moved the session into encrypted Supabase storage and proved the reload path end-to-end (log in → kill container → restart with no local file → still authenticated).
- Deploy gremlins. A local supabase/ folder shadowed the pip supabase package; the Railway Docker build hung for 20 minutes on an interactive tzdata timezone prompt; WebSocket upgrades don't proxy cleanly through Next.js rewrites (so the VNC stream connects to the backend directly). Each was a small fix that cost real time to diagnose.
- Making automation safe. For the email watcher, "mostly right" isn't good enough — wrongly marking a job "rejected" is worse than doing nothing. We made every model output schema-validated and every state change deterministic, with a human-review queue for anything ambiguous.
- Merging many people's work into one product. Multiple slices (scraper, email, interview, profile, UI) landing in one repo meant real merge conflicts in shared files like the dashboard layout, resolved carefully so nobody's work regressed.
Accomplishments that we're proud of
- A job-hunt flow that's actually end-to-end and working, not a stitched-together demo.
- Logging into LinkedIn from the browser via a streamed remote browser — 2FA and CAPTCHA included.
- Encrypted session persistence that genuinely survives restarts (verified live against real Supabase).
- An email→application-status automation that is safe by design — it never takes an action it isn't confident about.
- Engineering discipline throughout: test-driven development, encrypted secrets, and graceful fallbacks (the app runs unauthenticated instead of crashing when there's no session).
What we learned
- The hard edges of browser security — why a session can't be lifted client-side, and how to work with that instead of against it.
- How to stream a server-side browser (Xvfb / x11vnc / noVNC) and ship it inside Docker alongside Playwright.
- The realities of deploying to Railway/Vercel: $PORT binding, non-interactive apt, single-instance in memory state, and proxying HTTP vs WebSockets differently.
- How to design trustworthy AI automation — validate everything, keep the state machine deterministic, and fail to human review.
- The genuine trade-offs of single-user vs multi-user — storing other people's LinkedIn sessions is a real custody and terms-of-service responsibility, so we scoped deliberately.
What's next for Athena AI
- Multi-user with real authentication and per-user encrypted sessions.
- A smoother login: a username/password form that only falls back to the streamed browser when LinkedIn throws 2FA/CAPTCHA.
- Session health & auto-recovery — proactively detect expiry and prompt reconnect before a scrape fails.
- Deeper CV tailoring with full traceability (every tailored line traces to a real resume bullet) and draft auto-apply.
- Calendar & reminders for interview stages, and unifying the two backends behind a single gateway.
Built With
- fastapi
- javascript
- nextjs
- python
- typescript
- vllm
Log in or sign up for Devpost to join the conversation.