Skip to content
Brijesh.

Case study

Application Pipeline

I automated my own job hunt, and learned where to not trust a model

Sector
product
Year
2026
Role
Everything
Live
Internal tool — no public URL
model providersrouted by task, not by preference
3
capableinstallable PWA, local SQLite
offline
  • Next.js 16
  • React 19
  • TypeScript
  • Tailwind CSS v4
  • SQLite (better-sqlite3)
  • Anthropic SDK
  • Google Generative AI
  • Groq SDK
  • Playwright
  • Zod
  • PWA / Service Worker

01

What it does

Listings are collected via headless browser automation, normalised, and stored in a local SQLite database. From there a pipeline view walks each role through tailoring, review and submission, and a tracker records what happened. Resume and cover-letter generation produce a real PDF, and approving a role generates both in one step.

It is a single-user local application by design. There is no account system, no hosted database and no server round trip for the data, because none of those would make it better and all of them would make it slower to use.

02

Three model providers, on purpose

The tool routes work to different providers by task rather than settling on one. Long-context reasoning over a full job description and resume goes to Claude. High-volume, latency-sensitive classification — is this listing relevant, is it a duplicate, does it match the criteria — goes to Groq, where inference is fast and cheap enough to run over hundreds of listings without thinking about it. Gemini handles a third class of extraction work.

The point of the abstraction is not provider-agnosticism as a virtue. It is that the cost and latency profile of 'read this carefully and write something good' is completely different from 'sort these five hundred things', and paying frontier prices for the second is how a tool like this stops being worth running.

03

Where I stopped trusting the model

The tailoring step originally had free rein over the resume. It produced better prose and, occasionally, quietly better job titles — an 'SDE 2' became a 'Senior Software Engineer', a scope grew slightly in the retelling. Every individual edit was defensible. Collectively they were a resume that misrepresented me, generated by a tool I built to help me.

So certain fields became structurally immutable: titles, dates, employers and metrics are pinned and the model cannot touch them regardless of what it is asked to do. It can select, order and phrase. It cannot change facts.

That is the transferable lesson, and it is the same one as the server-side cart validation two case studies up. A generative step is a system boundary. You validate at boundaries — you do not rely on the thing on the other side behaving well, and 'the prompt says not to' is not a constraint.

  • Factual fields pinned outside the model's reach; generation is limited to selection and phrasing
  • Zod schemas at every model boundary — an unparseable response is a handled error, not a crash
  • All state local: SQLite on disk, no hosted data
  • Installable PWA with a service worker, so it works on a train