The problem
The best roles never reach a board
Aggregators index public, structured listings. The best roles in early-stage AI surface as a paragraph in an operator's newsletter or a founder's LinkedIn post. They're gone in a day and no aggregator ever sees them.
Black boxes everywhere
Auto-apply tools spray at scale. Resume tailoring rewrites freely and sometimes invents facts. Fit scores are opaque percentages with no rubric you can inspect, question, or edit.
Your search lives on vendor infra
Comp targets, unpublished leads, resume drafts. All of it sits in someone else's database, feeding someone else's product.
I cared about precision over volume: I'd rather review ten well-matched, honestly-tailored applications than auto-submit two hundred. No commercial tool is built for that, so I built it myself. One user, one Windows machine, full control over the data and the rubric, and a clear line where the automation stops.
Who it's for
Built for one demanding user (me, running a targeted job search), which made it an honest testbed. If a score was wrong, I felt it the same day, and the rubric got edited that evening.
The reason it belongs in a portfolio: every operating team has a version of this problem. High-volume, low-structure signal scattered across sources, where a miss is expensive and human review doesn't scale. Talent sourcing, competitor monitoring, and inbound qualification all have the same shape. The stakeholders map over directly. An operator needs a ranked queue with reasons they can interrogate. An approver needs unit costs and an audit trail before funding it. Governance needs a guarantee that the system observes and assists but never acts outward on its own. All three were designed in from the start.
The approach
Every posting, from any source, lands in one place: parsed, scored 0–100 against a rubric I wrote (fit_profile.md), and ranked. Triage becomes a two-minute decision pass. Apply, Later, or Pass.

What it does, end to end:
- Finds roles aggregators don't cover. Substack newsletters from operators and investors, specific people's LinkedIn activity (via Apify, no LinkedIn login), a startup job board, plus a one-click Chrome extension and a paste-a-JD CLI for anything auth-walled.
- Scores against a rubric, not an embedding. An explicit set of role types, push/pull factors, and a soft comp floor that I wrote and can rewrite anytime. Haiku extracts structure from raw prose; Sonnet makes the judgment call. Every score cites its reasons: what cleared the bar, what dragged it down, what needs a human check.
- Never scores thin data. A newsletter mention is a blurb, not a job description, and scoring a blurb produces noise. Sparse captures go to a queue where an enrichment worker finds the real posting first.
- Tailors a resume per job. It selects, reorders, and rewords from one master resume and is forbidden from inventing facts. A scoring pass grades the result against the JD, and a grounding audit flags any claim that doesn't trace back to the master. A revise loop turns checked issues into a measurable before/after score, then exports print-ready HTML or a .docx in my real CV layout.
- Autofills ATS applications on Greenhouse, Lever, and Ashby. Contact fields come from a local profile; free-text answers are drafted for review. EEO questions, consent checkboxes, and file uploads are never touched. Nothing is ever auto-submitted.
A score you can interrogate is a score you'll trust, and trust is what separates a tool that gets used daily from a dashboard that gets ignored.
Architecture
The diagram above is the simplified view; the full one, exported from the project itself, opens from the corner link. Three OS processes run independently: collectors on a two-hour schedule, an always-on enrichment worker, and the dashboard server. They share a single Excel workbook and coordinate through the filesystem. No message queue, no database server. At this scale none of that earns its keep, and every piece added is a piece one person has to operate.
The workbook is the single source of truth. A file-lock-aware pending queue serializes any write that fails because Excel has the file open, then replays it on the next writable operation, so I can keep the workbook open while the crawlers run. The only outbound calls anywhere are Anthropic and Apify, and every LLM call from every process lands in a structured usage ledger.

Architecture decisions & trade-offs
The calls that shaped the system, in the order the project forced them, including two that were revisited after being wrong.
Excel as the database, not a database
One .xlsx, accessed only through a single module that owns the file-lock contract. No concurrent writers, no transactions. In exchange: zero infrastructure, a format I already live in, and debugging that amounts to opening the file. For a single-user tool that trade is worth making on purpose.
Local-first, nothing outbound
The only network calls are Anthropic and Apify, both necessary and both auditable in the usage ledger. The price is no cross-device access. Fine. Comp targets and resume drafts shouldn't sit in someone else's database anyway.
Structured output via tool-use, not regex
Every shaped answer goes through Claude's tool-use against a JSON schema, with one retry on malformed output. Parsing free-text LLM output is a maintenance trap this design never enters.
Model tiering, held to
Haiku for extraction, Sonnet for judgment, no Opus anywhere. The constraint survived every new feature because each call site gets audited rather than assumed.
Why enrichment exists at all
Most of the best leads arrive as one-line mentions with no job description attached. You can't score what you can't read, so a background worker finds the real posting first. Each retry searches differently (broad web search, then ATS-scoped exact phrases, then aggregator boards), since repeating a failed search just fails again. Its autonomy stays narrow: decide whether a candidate page is the real posting, nothing else.
The sparse-capture rule, learned the hard way
Early on, mentions that had a link were scored directly. A score computed from a two-sentence blurb turned out to be too weak to gate on. The fix was a rule with no exceptions: every sparse capture goes to the enrichment queue, and only a fully-parsed JD gets scored for routing. A migration recovered the rows the old logic had mis-filed.
Never automate the parts with trust exposure
Autofill fills contact fields and drafts answers for review. EEO self-identification, consent boxes, and file uploads are off-limits, and nothing auto-submits. Narrower than auto-apply, on purpose. The boundary sits where assistance turns into consequence.
A usage ledger, added after log-scraping failed
The first cost tracker scraped logs and silently missed an entire process whose launcher never redirected output. Now the API wrapper appends one record per call, from every process, unconditionally. A metrics system should be verified complete, not assumed complete.
Build roadmap
Built in stages. Each one shipped and got daily use before the next started.
Discovery core
Excel store with the file-lock contract, LLM parse and score, capture server, triage view, Substack and startups.gallery crawlers, Windows scheduler.
Routing + real dashboard
A fit threshold that actually gates what I see, full tabbed views, the Interview Tracker editable in place, migrations to backfill it all.
Enrichment worker
Sparse-capture handling and the escalating-retry search loop. Survived two real billing incidents, each becoming a failure classifier that aborts a cycle instead of burning retries.
LinkedIn source
A community Apify actor, no login required, covering the single richest source of unlisted roles.
Dashboard v2
Batch triage, a human-override feedback loop that shifts the displayed score without touching the model, filter and sort tooling, a company-to-LinkedIn resolver.
Apply assist
Per-job tailored resumes in my real CV format, a resume scorer with a grounding audit, ATS autofill with the automation boundary drawn explicitly.
Copilot side panel
A second Chrome extension that runs analyze, tailor, score, revise, and fill as one guided sequence, with background execution that survives the panel closing.
Usage & Sources
Cost tracking and source management promoted from buried code to self-service dashboard pages. This is where the usage-tracking gap got caught.
Business impact
These come from the live usage dashboard and move continuously; read them as scale and unit economics rather than fixed claims. Every LLM call from all three processes lands in a structured ledger, and the spend estimate is reconciled against Anthropic's own billing API.

The counts matter less than what's visible: cost per model, per pipeline stage, per activity. Anyone asked to approve an AI workload should demand this view before scaling one, because a cost per processed item is an argument and a monthly bill is an apology.
How it compares to JobRight & similar tools
This isn't strictly better than commercial tools. It optimizes for a different point in the trade-off space, and it's worth being specific about which.
++ Where this wins
- Unlisted signalFollows newsletters and founder posts that never reach a job board, which aggregators structurally cannot index.
- Inspectable scoringA rubric you can read and edit, instead of a black-box match percentage.
- Thin data handled honestlyA teaser never gets scored as-is. The real posting is found and re-scored before it counts.
- Grounded resume tailoringRestricted to one master resume, with an audit that flags any claim that doesn't trace back.
- Cost transparencyTracked to the cent, per job and per activity, reconciled against real API billing.
- Data ownershipNothing leaves the machine except two necessary, auditable API calls.
− Where commercial tools win
- CoverageThousands of listings across every industry, against a few hundred curated postings here.
- Polish & convenienceCommercial products have design teams, mobile apps, and onboarding. This has a localhost dashboard.
- Zero setupA subscription works on day one. This needs API keys, a Windows machine, and an owner who codes.
- Multi-user scaleBuilt for exactly one user. No accounts, no sharing, no team features.
Commercial tools win on coverage and convenience because they serve a much broader search. This wins when the search is narrow and the best opportunities were never going to show up on a board. You build the tool yourself when the search is the differentiator, not the software.
Risks & guardrails
- Nothing outbound, nothing auto-submitted. The system discovers, scores, tailors, and drafts. A human reviews and sends everything.
- Rejected items are kept, so every auto-reject stays auditable and scoring drift shows up instead of hiding.
- The rubric is versioned, and a human override shifts the displayed score without overwriting the model's, so you can tell whether the market moved or the rubric did.
- Tailoring is grounded. Select, reorder, and reword from one master resume; a separate audit flags anything that doesn't trace back.
- Spend can't run away. Batch cadence, dedup before any LLM call, prompt caching, and model tiering tie cost to new signal rather than raw volume, and billing failures abort a cycle instead of burning retries.
Where it goes next
Interview transcription and cross-interview pattern analysis, already scoped. That closes the remaining loop, from "found the job" to "learned something from how the interview went." And the enterprise version of this pattern, same pipeline pointed at different signal, is the pitch I'd make to any team drowning in unstructured inbound.