← All work
Case study · Independent build · Solo, end to end

Job Agent

A multi user AI job hunt agent that works while you sleep. Once a day it finds roles across job boards, scores each one against your resume, tailors a resume variant and outreach draft for the strong matches, and tracks every application on one pipeline board. I defined the product, built the agent and the app, designed the interface, and shipped it.

Job Agent · pipeline
Job Agent pipeline board with the strongest match promoted to a featured card and the fit score shown where a salary would normally sit
Agentic workflow LangGraph RAG fit scoring Full stack, solo Next.js · Supabase
9
User stories shipped
5
Agent steps in the run
56
Automated tests, all green
Daily
Autonomous scheduled runs
The problem

Job hunting is a part time job made of repetitive, low leverage work. You search the same boards every day and most of what you find is noise. You eyeball each posting and guess whether you are a fit. For anything promising, you rewrite your resume and a cold note from scratch. Then you lose track of what you applied to and what came back.

The judgment is the valuable part. The searching, the scoring, the rewriting, and the tracking are not. That is exactly the kind of grind an agent should own, while the person keeps the decisions.

So I built Job Agent to run the loop for you. You onboard once, and the agent works every day: it finds roles, scores each one 0 to 100 for fit with a reason, tailors a resume and outreach draft for the strong matches, tracks everything on a pipeline board, and emails you a short digest of what it found. You stay in control of who you actually apply to.

How the agent works

The run is a five step loop. Each step does one job and passes its state to the next, so the agent is predictable and every stage is testable on its own. Here is what happens once a day, framed as the product steps a job seeker actually cares about.

1 · Find and dedup

It gathers roles from real job board feeds, then fingerprints and liveness checks each one so the same posting never lands twice and dead listings drop out before they reach you.

2 · Score for fit

Every role is embedded and scored 0 to 100 against your resume. The score combines a semantic similarity signal with an LLM judgement that returns the reason, the matched skills, and the gaps.

3 · Branch on the threshold

Only roles above your fit threshold move on to tailoring. Borderline roles still get a score and a reason, but no draft, which keeps token spend tied to roles worth acting on.

4 · Tailor and track

For the strong matches it writes a tailored resume variant and an outreach draft, persists everything to your pipeline, and sends a short email digest. Applying becomes an edit, not a blank page.

The point of the loop is leverage with a human in the seat. The agent does the searching, scoring, and drafting every single day, and you spend your time only on the strong matches it surfaces. It is assisted apply, not auto apply: a person still reviews and submits every application, by design.
Architecture

This is the part I am most proud of as a product and engineering decision, not just a build. The two diagrams below encode the calls that make Job Agent safe to run for many users, free to run on a schedule, and easy to reason about one step at a time. The captions are the decisions, not descriptions.

System architecture: a Next.js app on Vercel, a Supabase data layer with Row Level Security, a LangGraph agent with local embeddings, and a GitHub Actions daily cron
I made the system multi tenant in the database, not the app. Every per user table runs under Postgres Row Level Security, so the database itself refuses cross user reads and writes, rather than me filtering by user in code and hoping I never miss a query. I run the embedding model locally with MiniLM so there is no per embedding API cost, and because that needs a native runtime Vercel serverless does not give me, I moved the daily run onto a GitHub Actions cron with a secret gated endpoint as the fallback. The free local model stays free.
The agent run as a LangGraph state machine: trigger, gather, dedup, score, branch on fit threshold, tailor, persist, notify
I built the run as a LangGraph state machine instead of one long script, so each node, gather, dedup, score, branch, tailor, persist, notify, is isolated and testable and easy to extend. The branch on the fit threshold is deliberate: tokens are only spent tailoring roles worth acting on. And the final shape is assisted apply, never auto apply, so a human reviews and submits every single application. The agent owns the grind, the person owns the decision.

Every screen below uses a demo account with synthetic data, never a real user's job search.

Onboard once, then step back

You upload a resume and tell the agent what you are hunting for: target roles, locations, salary, company types, deal breakers. This is the only manual setup in the whole product.

After this, the agent knows exactly what to hunt for, and the daily run takes over. Everything else on this tour is the agent's output, not work you do by hand.

Onboarding: upload a resume and set target roles, locations, salary, company types and deal breakers

The pipeline board

Every match lands on a Kanban board and moves through Matched, Reviewed, Applied, Replied. The strongest match is promoted to a featured card so the best thing the agent found is the first thing you see.

The fit score sits where a job board would normally show salary, because fit is the number that actually matters here. You never lose track of where each role stands.

Pipeline board with matched, reviewed, applied and replied columns, a featured top match and a fit score on every card

Why a role fits, and a draft ready to send

Open any role to see the fit breakdown: the reason, the matched skills, the gaps, and the recommended resume variant. So you can decide fast and prep for the gaps before you ever apply.

Below it, the agent has already written a tailored resume and an outreach draft for that role. Applying is an edit, not a blank page, so it takes minutes instead of an hour.

Job detail showing the fit reason, matched skills, gaps, the recommended resume variant and a tailored outreach draft

Know if it is working

Analytics turns the hunt into numbers: the pipeline funnel, the fit score distribution, which sources produce the best matches, and matches over time.

It answers the only question that matters once the agent is running, which is whether the hunt is actually converting, without anyone pulling a report.

Analytics with a pipeline funnel, a fit score distribution, best performing sources and matches over time

Every run, on the record

The agent runs daily on a schedule. Each run records what it found, scored, matched, and tailored, plus the token usage and cost for that run.

Failures are logged with a reason, not hidden. The work the agent does while you sleep is fully auditable the next morning.

Runs log showing each daily run with counts found, scored, matched and tailored, plus token usage, cost and any failures

Tune it over time

Settings is where the agent gets sharper the more you use it: manage resume variants, keep your applicant profile current, and adjust the preferences that drive matching.

The agent is not static. As you refine what you want, the scoring and the matches sharpen with you.

Settings with resume variant management, the applicant profile, and the preferences that drive matching
From working to wanted

The first version was correct but it looked like a raw scaffold: default font, black on white, cramped, no identity. The logic worked, but nobody would trust it with their job search. So I ran a focused design pass.

I anchored the visual direction on a job board portal concept, light and airy with rounded cards and a single signature gradient reserved for the standout match, and built a real design system for it: Plus Jakarta Sans, a calm neutral canvas, soft shadows, color coded fit scores, and pill based tags and controls. The system lives as design tokens in one CSS file and a set of shared primitives, so all eight surfaces stay consistent and the whole look can be retuned from one place.

The first version of the dashboard: a correct but unstyled raw scaffold, default font, black on white
Before. Correct, but it looked like a raw scaffold. Same data, same logic, no identity.
The redesigned pipeline board with a real design system, a featured top match and color coded fit scores
After. The same data and logic, now a product that looks like something you would trust with your job search.
Tech & tools
Next.js 16 React 19 Tailwind Supabase (Postgres, pgvector, Auth, Storage, RLS) LangGraph Local MiniLM embeddings OpenAI SDK GitHub Actions Resend Vercel

Built and shipped solo by directing AI coding tools across the full stack, the same way I ship every product I take on.

My role
  • Defined the product. Took a fuzzy, familiar problem and turned it into a multi user agent with nine clear user stories, each mapped to a real screen.
  • Built the agent. Designed and built the LangGraph run: gather, dedup, score, branch, tailor, persist, notify, with local embeddings and an LLM fit judgement.
  • Designed the interface. Built a real design system and applied it across all eight surfaces, taking the product from a raw scaffold to something worth trusting.
  • Shipped and deployed it. Live on Vercel with auto deploy on push, a daily GitHub Actions run, Resend email digests, and 56 automated tests green.

Want the full walkthrough?

I am happy to demo Job Agent live and talk through the product decisions, the agent design, and how I scoped, built, and shipped the whole thing solo.