All work
06/Career tools

KairosAI

An end-to-end job-search platform — from "here is my CV" to "the application is submitted".

Domain
HR-tech · career tools and job-search automation
Status
MVP — feature-complete and demonstrable end to end; not commercially launched
01

The challenge

Applying for jobs is a volume problem disguised as a writing problem. A serious search means a hundred-plus applications, and almost none of the work in them is interesting: retyping the same employment history into a different form on every site, rewording the same resume to match the vocabulary of each posting, and doing it across several job boards that have no knowledge of one another.

Underneath that sits a filtering problem the candidate can't see. Most applications at any scale are screened by an ATS before a person reads them, which means a well-qualified candidate whose resume doesn't use the posting's vocabulary is rejected by a keyword match rather than a judgement. Candidates are asked to optimise against a system whose rules are never shown to them.

The tooling that exists solves one slice each. A resume builder doesn't know what jobs are open. A job aggregator doesn't know whether you're a fit for what it's showing you, or whether your resume will survive the filter. Interview practice needs another human, or costs money, or both. So the candidate ends up as the integration layer between four tools, doing the joining by hand — which is exactly the part that makes the process exhausting.

02

Our role

The product was divided by domain: each of three people owned the data model, backend service and front end for their own area, composed into one application.

Our slice covered the two halves at the front of the funnel — the resume pipeline (ingesting an uploaded resume, extracting it into structured data, optimising it against a target posting, running ATS keyword analysis, and classifying the candidate as junior, mid or senior), and the job collection and matching engine (the scraping and normalisation layer, and the hybrid matching system that scores listings against a candidate profile).

The mock-interview chatbot and the browser extension were owned by a teammate. Both are described below, because the case for the product is that these pieces only matter as one loop — the extension is only useful because the resume is already structured, and the interview practice is only targeted because the matching engine decided which role the candidate is preparing for.

03

What we built

Three pillars sharing one candidate profile: understand the candidate, find and rank the work, then actually get the applications out of the door.

Pillar A — Resume intelligence

The candidate uploads a resume and it stops being a document. It's parsed into structured data — roles, dates, skills, projects, education — which is what makes everything downstream possible, including the autofill.

  • Parsing and structuring — an uploaded file from any template ends up the same shape as any other.
  • Optimisation and ATS keyword analysis — the resume is compared against a target posting and rewritten to match the vocabulary the filter is looking for, with the keyword gaps surfaced to the candidate rather than silently patched.
  • Seniority classification — junior, mid or senior, which becomes the primary filter on what gets recommended. Showing a junior candidate senior roles isn't a neutral failure; it wastes the applications they have the energy to make.

Pillar B — Job collection and matching

  • Collection — job pages fetched and parsed as scheduled batch jobs, each board handled by its own extractor, everything normalised into a shared job record.
  • Hybrid matching — a listing is scored three ways: semantic similarity between the structured resume and the posting, keyword matching against the terms the posting actually uses, and an LLM pass for the judgement call. The three signals combine into the recommendation.
  • Tracking — a dashboard of what's been applied to, what stage it's at, and what's still open, so the candidate isn't managing a hundred applications out of their inbox.

Pillar C — Interview practice and application automation

  • Mock interviews — a chatbot conducting practice interviews in text and voice, then scoring the candidate and giving feedback on the answers rather than just ending the conversation.
  • Autofill browser extension — reads the application form on the page, matches its fields against the stored resume data, and injects the values. It works across a wide range of sites rather than a fixed list, and on selected sites carries the application through to submission.
04

Stack

Technology stack, by layer
LayerWhat we used
AI / ML
  • GPT-4o mini across the whole product — parsing, optimisation, ATS analysis, classification, match scoring, autofill field matching, and interview conversation and feedback
  • embedding-based semantic similarity alongside keyword matching
  • speech in and out for voice interviews
Frontend
  • Next.js
  • React
Backend
  • Node.js
  • Express, split into per-domain services owned separately
Data
  • Supabase — PostgreSQL for application data, auth, and object storage for uploaded resumes
Scraping
  • Cheerio-based HTML parsing over scheduled collection jobs, per-board extractors normalising into one schema
Extension
  • Reads the rendered form, model-matches fields against the stored resume, injects values, submits on selected sites
Infrastructure
  • Vercel
05

Decisions

Decision01

Autofill by reading the page, not by maintaining selectors

The conventional way to build a form-filling extension is a rule per site: a hand-written map of CSS selectors to fields for each employer's form. That's straightforward, and it's also why most autofill tools support a short list of sites and break constantly. Application forms are built by thousands of companies on dozens of ATS products, every one free to change its markup on any given day, and no small team keeps a selector table current against that.

So the extension carries no selectors. It reads the form as rendered, and the model matches the fields it finds against the structured resume — deciding that this input wants a phone number and that textarea wants the current job description — before injecting values. The consequence is that it generalises: it works on forms nobody wrote a rule for, including forms that didn't exist when it was built. That's also the clearest payoff from Pillar A, since matching a form field to a candidate is only tractable because the resume was turned into structured data at upload.

Decision02

Hybrid matching rather than picking one technique

Each of the three obvious strategies fails alone. Pure keyword matching is brittle and misses every candidate who says "built REST services" where the posting says "API development". Pure embedding similarity captures that equivalence but happily rates a related-but-wrong role highly, because semantic closeness isn't the same as being a fit. An LLM asked to judge every listing is the most accurate and by far the most expensive, and doesn't scale across a full board of postings.

The system runs all three. Keeping keyword matching in the loop is the non-obvious part — it isn't there because it's a good similarity metric, it's there because it models the filter the candidate is actually up against. It's signal about whether the application will survive, not merely whether the candidate is suitable.

Decision03

Scraping as scheduled collection rather than live fetching

The naive design fetches listings when the user asks for recommendations. That makes the user wait on someone else's server, makes the request rate look exactly like the traffic pattern boards watch for, and re-fetches the same postings for every user who searches.

Collection instead runs as scheduled batch jobs writing into a normalised store, with matching done against that store. The user's request touches the database and nothing else, which is why recommendations are fast, and the collection rate is decoupled from how many people happen to be searching.

Decision04

Consolidating two Postgres providers into one

The project began with data split across Neon and Supabase. Both are PostgreSQL, which is what made the split look harmless — and what made it a genuine drag. Auth and resume file storage already lived in Supabase, so the split meant two connection stories, two sets of credentials, two places to look when something was wrong, and a boundary to reason about every time a query wanted to join across it. For a three-person team on a seven-month timeline that's a tax paid continuously for no benefit.

Neon was dropped and everything moved onto Supabase. The lesson worth recording is that the migration was cheap precisely because it was done early — the same decision deferred until the schema was fully grown would have been a project rather than a change.

Decision05

One model tier across the whole product

Every AI call runs on GPT-4o mini. A larger model would have improved the judgement-heavy calls, particularly match scoring and interview feedback. On a project with no revenue and a seven-month clock, running one cheap model everywhere is what let all three pillars get built and demonstrated rather than two of them being built well. It's the right call for an MVP, and the first thing worth revisiting if the product went further.

06

Results

A completed project delivered as an MVP, not a launched product. No usage, accuracy or revenue metrics were collected, so none are reported here.

0
Integrated pillars, one candidate profile
Results
Scope deliveredThree integrated pillars — resume intelligence, job collection and matching, and interview practice with application automation — working end to end against one candidate profile
Commercial modelThree tiers designed into the product (Starter, Pro, Elite), separated by application volume and how much automation is unlocked. Never taken to market; no revenue
Extension coverageGeneralises to application forms with no per-site rule written
07

Screenshots

KairosAI landing page — upload a resume and get matched to live listings
Landing page
KairosAI pricing — the Starter, Pro and Elite tiers described in the case study
Pricing tiers