WORK

I built a system to decide which jobs were worth pursuing

Resume Signal Framework · Independent Build · January–September 2026

Somewhere early-ish in my job search, I realized I was asking myself the wrong question.

I’d find a job that looked interesting, read the description, and start figuring out how I’d make the case for myself. Could I actually do this job? Almost always, yes. That’s not the same question as whether the job was worth pursuit.

A job can be within reach and still pull me away from where I actually want my career to go. The title can look right while the responsibilities are wrong. The comp might not work. Or I might technically qualify without having evidence that would make me an obvious candidate to whoever’s actually screening applications.

And every application had a real cost: researching the company, tailoring the resume, writing a cover letter, applying, tracking it, then getting ready in case someone called. I was making that investment over and over without a consistent way to decide whether I should. Enter burnout. So I started building a solution.

It started as a framework

My job search started in December ’25. Resume Signal Framework (RSF) didn’t. For the first month it was just me and Chat GPT having roughly the same conversation over and over, informally, without much consistency. The actual practice, a repeatable way of scoring a job instead of just reacting to it, starts showing up in mid-January ’26, about a month in.

“So I built a simple system I’ve dubbed the Resume Signal Framework. It’s an AI-powered system that consistently evaluates job descriptions against my experience, scope, and goals. I get a score, a grade, and a clear pursue or do-not-pursue recommendation… Think of it as a personal CRM for job search decisions.”

— LinkedIn, January 16, 2026

Instead of reacting to a job description, I wanted to separate a few things I’d been blending together: what problem the company was actually hiring somebody to solve, what evidence I had that I’d solved something like it before, and how obvious that evidence would be to someone who’d never met me. Then, separately even if all of that lined up, did I actually want the job?

That last question turned out to matter more than I expected. Early versions of the framework were mostly concerned with fit. Over time I realized a high-fit job wasn’t automatically a high-value one.

So it evolved. RSF splits the judgment into four separate measures instead of one blended score, on purpose. Truth Score is pure capability: can I actually do this job, based on evidence, with no adjustment for comp, location, or whether I even want it. Bucket is a different question: how would a recruiter perceive this candidate in a fast scan, independent of anything about what I want. Strategic Adjustment is where my own preferences and career strategy come in: comp, company stage, direction, the stuff a job description alone can’t tell you. And Pursuit Score is Truth plus Strategic Adjustment, added together and turned into a letter grade, computed on the server: never something the model touches.

A role can score high on Truth and still land a mediocre Pursuit Score. That’s was my intention of splitting them: a role I could obviously do isn’t automatically one I should want.

Using it changed it

I didn’t design the full framework and then start using it. I used it, found where it broke, and changed it. That happened over and over, and the clearest example of it happened on July 3rd.

I’d been running two versions of RSF side by side for a while: the manual version, my own judgment applied to a JD by hand, and a Beta app I’d started building to do the same evaluation automatically. On July 3rd, both versions looked at the same job: a Head of Lifecycle Marketing role at Upstart, and came back with wildly different verdicts. My own manual read had it at 89, an A-. The app had it at 62, a D-.

That’s not a rounding difference. It was two versions of the same framework disagreeing about whether a job was worth pursuing at all.

The cause was straightforward once I saw it: the app’s single score was letting strategic and preference factors, things like comp or company stage, drag down what was supposed to be a pure read on capability. My manual judgment wasn’t making that mistake, mostly because I was doing that separation in my head without noticing it was a separate step. The app was doing it all in one number, and one number couldn’t hold both questions: whether I could do the job, and whether I should want it, without one contaminating the other.

Two days later, on July 5th, I shipped the fix: Truth Score became strictly capability-only, and everything about preference and strategy moved into its own number. That’s the actual origin of the four-way split described above. It didn’t come from a design session. It came from the system disagreeing with itself badly enough that I had to stop and figure out why.

By that point I wasn’t the only one testing it, either. A handful of other people had tried the Beta by then, including someone who came back and ran it several times over a few days without my asking. I don’t have a clean record of how many of those evaluations turned into actual applications. I never built that link. But there’s a dated log of RSF evaluations running from mid-January through the end of July, and by July it wasn’t just me looking at it.

Then I turned the process into software

For a long time, RSF was useful to me without needing to be an app. Eventually that stopped being true. If I had to reconstruct the process by hand every time, too much of it still lived in my head and in whatever AI conversation I was having that week.

So I built something around it, in June. A user gives it a job description and their own candidate context; RSF hands back scores, fit factors, recruiter concerns, evidence gaps, a read on the actual business problem behind the role, and a recommendation. One of the first things I built into it was a way to ask not just what the score was, but what was capping it. That question had actually been part of how I thought about roles for months before the software existed. The software just caught up to something I’d already been asking myself since the second or third week of doing this by hand.

I didn’t want the model responsible for everything, though. I use it where interpretation actually helps: making sense of a messy job description, weighing it against my evidence, figuring out what a company’s actually hiring for. Everything downstream of that stays deterministic: the usage limit gets checked before the model is ever called, the output has to fit a fixed structure, the server does the arithmetic and decides the letter grade, and candidate context lives in the browser, not on my server. I don’t keep a history of anyone’s analyses.

Making it public created new problems

Something changes once a tool stops being something you run for yourself and becomes something anybody can use. The model costs money every time someone runs an analysis, so public access needed real limits: a rolling usage cap enforced by a counter outside the app itself, with an override for people who legitimately need more, checked before the paid model request goes out.

I also wanted to know whether the thing was actually getting used, without storing anyone’s resume or job description to find out. So there’s a lightweight usage log: company, role, score, grade – that never touches the actual candidate material.

The ledger failed quietly in the background

For a while, that log just… stopped picking up new entries. Nobody could tell, it was working just fine. Every analysis still came back fine. It happened during the same week I was doing the final hardening before I took it went public.

The actual problem was that the Google Apps Script webhook behind the log was returning a normal HTTP 200, with an error tucked inside the response body: something like ok: false. My server was only checking whether the request itself had succeeded, not what was actually in it. A rejected write and a successful one looked identical from my vantage point.

Finding it took a bit of ruling-out. A token mismatch, a stale deployment, a JSON-escaping issue, checked one at a time using a local stand-in for the webhook so I didn’t have to touch production to test it. The fix itself was small once I found it: actually read the response body, treat ok: false as a real failure, log it clearly. I kept the whole thing non-blocking on purpose. A broken log shouldn’t be the reason someone’s analysis fails.

Deciding what shouldn't be built

I could keep adding to RSF: accounts, saved analyses, payment, more history, more automation. None of that would be hard to justify. It’s also not necessary. The thing already does the job I built it to do, so I left it alone and drew a boundary around the public version instead: candidate profile stays in the browser, there’s no server-side history, public use is capped, and the actual scoring prompt, the real methodology, stays private.

Then I split it up. The live app runs off a private repository. Separately, I put together a curated public repository that shows the real architecture: the rate limiter, the structured-output pattern, the Apps Script integration, a runnable slice of the test suite, all without the scoring prompt that actually makes the evaluation work.

Before that public repo went live, I went through it specifically looking for anything that shouldn’t be there. I found two things: the exact Bucket taxonomy and the exact numeric range behind Strategic Adjustment, both sitting inside what was supposed to be a sanitized example. I pulled them, then checked the git history and found they were still recoverable from an earlier commit. So before the repository ever went public, I rewrote its history down to a single clean commit and pruned the rest, then checked again for secrets, tokens, credentials, production identifiers, anything personally identifying, and any remaining trace of the real methodology, before I actually published it.

Resume Signal Framework is a live tool now. There’s a dated record of me running some version of this on real jobs from mid-January through the end of July. That’s about six and a half months before any of it was public, and before most of it was even software. The public repository and the rate limiting went in this past week.