G.B.
Creator · 2026 – Present

CareerOps

A full-stack platform that turns a raw job posting into a scored decision and ready-to-send documents in minutes: evaluate, tailor, track, and assist the application, with a human always in the loop.

Next.jsTypeScriptNode.jsGemini APIPlaywrightTailwindYAML
100-pointDeterministic eval rubric
3+ATS platforms auto-filled
MinutesPosting to documents
Human-onlyFinal submit
localhost:3000/discovery
CareerOps pipeline: discover, evaluate, tailor, assisted apply, and track
01

The Problem

Searching for a job at volume means running the same tedious loop hundreds of times: read a posting, judge whether it fits, tailor a resume and cover letter, then track where you applied. Doing it well by hand does not scale, and doing it fast usually means doing it generic.

02

Research

CareerOps started as a fork of an open-source job-search CLI framework. The base gave me a tracker and the idea of scoring a job before applying, but everything a person actually touches during a search, I built on top.

The core research question was trust. An AI that scores a job "85, apply" is worthless if the same posting scores 60 when pasted as text and 85 when pasted as a URL. So before any generation, I designed a scoring layer that strips ATS and legal boilerplate, normalizes both text and URL input through the same cleanup, and runs a deterministic 100-point rubric rather than asking a model for a vibe.

The second question was safety. Automating job applications is a fast way to submit garbage to real employers, so I decided early that the system would prepare everything and a human would always press the final button.

03

The Solution

The web app is a Next.js frontend over a set of Node.js pipelines. You paste a job or import a saved posting URL, an evaluation endpoint scores it against my profile with score guardrails (hard seniority requirements and missing must-have stacks can cap the score), and the result is a scannable score card, not a wall of text.

If the score is worth it, one action generates a resume and a cover letter tailored to that posting, canonicalized to one locked resume template and rendered to PDF. A portal scanner pulls fresh Canadian roles from structured Ashby, Greenhouse, and Lever sources with a 24-hour freshness mode, and ranks them so recent, relevant roles surface first.

The most careful piece is assisted apply: a visible Playwright browser resolves the real application page, fills high-confidence ATS fields, uploads the job-specific documents, and then stops. It never clicks final submit, never touches login or referral controls, and never scrapes LinkedIn or Indeed. Those stay import-only signals.

  • Deterministic 100-point evaluation with post-model score guardrails
  • One-click tailored resume and cover letter, rendered to PDF per role
  • Freshness-ranked portal scanning across structured ATS sources
  • Playwright assisted apply that stops before the final submit
  • Configurable Gemini model with task-specific fallback models
04

Technical Decisions

A deterministic rubric with guardrails instead of a raw model score

A language model asked to score a job drifts run to run and inflates scores from URLs. A fixed 100-point rubric plus backend guardrails that cap scores on missing hard requirements makes the same job score the same way every time.

Trade-off: The rubric needs maintenance as I learn what actually predicts a good fit, but predictable scoring is worth more to me than a clever black box.

Human-in-the-loop apply, never auto-submit

Auto-submitting applications risks sending wrong or low-quality material to real employers under my name. The assistant fills and uploads, then hands control back before submit, so speed never costs me my reputation.

Import-only for LinkedIn, Indeed, and Glassdoor

Scraping those platforms violates their terms and risks account bans. I take saved job URLs and alert signals from them instead, and only scan sources with structured, permitted endpoints.

Trade-off: I give up some discovery volume, but the system stays compliant and I can defend every source it touches.

One locked resume template

The generator tailors content, but the visual format is fixed to a single approved template. That keeps every generated resume consistent and ATS-safe, and separates content decisions from design churn.

05

What Didn't Go As Planned

The same job scored differently depending on whether I pasted text or a URL, which made the score untrustworthy.

Routed both inputs through one normalization layer that strips boilerplate before scoring, and added backend guardrails that run after the model. Text and URL scores converged and stopped drifting.

Assisted apply kept stalling on posting pages that had no form, mistaking search and filter boxes for application fields.

Built a resolver that first checks whether visible fields actually look like an application form, then follows up to three safe Apply hops to reach the real form, while never clicking submit or login.

The free Gemini tier hits quota limits during heavy testing, which would break the pipeline mid-run.

Made model selection configurable with task-specific overrides and fallback model lists, and added offline scoring QA that tests the guardrails against fixtures without spending any API quota.

06

Outcome

100-pointEvaluation rubric
Greenhouse, Lever, AshbyATS platforms auto-filled
24 hoursDiscovery freshness window
Resume + cover letter PDFDocuments per role
Always manualFinal-submit control

CareerOps is the tool I actually run my own job search on, which means every rough edge gets found and fixed fast. It is the clearest proof that I build practical software: I had a real problem, and I engineered a system around it instead of grinding through it by hand.

07

Reflection

The honest limitation is that the whole thing runs locally for one user, me. If I rebuilt it for other people, the first things I would add are per-user profiles behind auth, a hosted queue so scans and generation run without my machine on, and evaluation metrics measured against real application outcomes rather than my own judgment of a good score.

Next projectMediTwinAI Health Companion