A job-search companion built for selective, hands-on use.
Switching resume retrieval from flat to chunked semantic embedding nearly doubled measured retrieval spread (5.9 to 12.6) across 3 job types, with an honest caveat: the effect is vocabulary-dependent, not universal.
Five models across three providers, each assigned by documented task-fit reasoning.
Bugs found and fixed with direct, measured verification.
Twelve years without a resume
I used AI in various capacities for real estate and investing for three years, namely to help with marketing and sales. Eventually, I started preferring the AI implementation work over real estate and decided I wanted to find a job that focuses on AI. The problem was that after 12 years of total employment, I had never needed a resume or cover letter. Furthermore, I was doing a career pivot, which meant my work required translation.
After 6-8 weeks of using ChatGPT to help refine my resume, I decided that I needed to solve for scale. Around that time, I saw some unsettling data from LinkedIn about job application conversion rates, and at my current volume it could reasonably take 10+ months. If I could scale the repeat labor, I would recapture time that would allow me to focus on improving my position (certifications, projects, etc.) and leaning further into the human element, like networking or getting involved in the community. Slowly my personal use evolved to a live deployment for my friend Grace, who was also pursuing a job transition while working full time.
Designed to use only verified facts
I built a tool that generates tailored resumes and cover letters from a job posting, built so that everything it writes traces back to something I actually did. It reads a job posting, pulls relevant facts from my own verified history, drafts a resume shaped to that specific role, and enforces hard limits on what it's allowed to claim. I review and can override every selection before anything goes out.
How it fits together
The following concepts are inspectable within the system map:
SSOT & guardrails
Every fact and claim is checked against one source of truth before it reaches a draft.
Onboarding
A new user's source of truth doesn't exist yet. Conversational intake builds it from scratch, and the user confirms every fact before anything goes live.
Per-application pipeline
Two tracks, one shared trust layer. Resume and cover letter generation both read and validate through the same SSOT and guardrails.
Self-serve profile agent
Facts change after onboarding too. Users update their own profile in plain language instead of editing config files by hand.
Portfolio tracking
Every application is more than a document. This tracks how it's actually progressing, alongside what was generated.
Inside the pipeline
Six techniques the per-application pipeline relies on.
RAG retrieval & dedup
Retrieval finds relevant bullets and blocks the same underlying point from being selected twice.
Human-in-the-loop gates
Two different checkpoints. A human answers open questions, then a separate model reviews before anything is finalized.
Grounded company research
Cover letters cite current facts about the company, pulled from a live web search.
Structured output validation
A generated response has to pass a schema check before it's used. If it fails, the pipeline retries instead of accepting something broken.
Multi-model orchestration
Five models across three providers are assigned by what the task actually needs and the LLM's relative strengths.
Context durability
One object carries an application's state through every pipeline stage, and every draft gets saved, so nothing has to start over from scratch.
Where the model stops and I start
Model-controlled
- Fit scoring against a job posting (
fit_scorer.py) - Drafting and synthesis: resume bullets, cover letters (
resume_writer.py,cover_letter_writer.py) - Gap reasoning (surfacing what's missing or thin,
gap_analyzer.py) - Independent review (a second model critiquing the draft cold,
independent_reviewer.py) - Rhetorical structure classification (
classify_transition_shape) - Grounded research and interpretation (
company_research.py)
Deterministic
- Forbidden-tool/phrase checks against
forbidden_claims.yaml, pure pattern matching, no model call (audit_resume.py) - Theme-collision dedup in retrieval (
primary_theme = themes[0]) - Schema/structure validation before a draft is accepted (
run_with_regeneration_gate) generation_statusfield validation (packet.py)- Strict binary claim verification, deliberately run on GPT-4o mini rather than Claude. Real documented reason: "GPT tends to be more literal and rule-following on structured checks than Claude, which is more interpretive. Interpretive is good for writing, not for audit."
Human-controlled
- Resume: transparent override. I can see the actual reasoning behind every bullet/skill selection (real scoring shown via the Compare drawers/Skills tab) and manually override any selection via drag-and-drop, without breaking anything downstream. It's built to be inspected and corrected.
- Cover letter: active co-authorship. I judge whether specific examples or transitions genuinely hold up for this application and add my own voice. It's the same reason I write my own cover letters by hand (see Results).
- Corrections can durably change the source of truth. Answering a gap or adding a missing fact updates the real SSOT, so future applications benefit too.
- My answer can be reused without re-asking (
apply_to_similarflag). Judgment compounds across a batch instead of being spent once per instance. - Explicit reject-and-regenerate is its own control, distinct from editing. When something is wrong, the move is a fresh attempt.
- Presentation/format choice (which visual preset renders) is a separate axis from content control entirely.
- Submitting the actual application (entirely outside the system).
Decisions that shaped the build
What keeps it accurate and reliable
Run on every generation:
1. Silent generation failure (found in live use)
generation_status, and the success path never set it either2. Theme-collision retrieval bug
primary_theme = themes[0] let a first-theme collision block a bullet regardless of its other themes3. PDF contact-column overflow
min-width: auto default)min-width: 0; overflow-wrap: break-word;What's real, what's estimated, what's next
The full pipeline runs end-to-end, job posting in, tailored resume and cover letter PDF out, confirmed across multiple real and synthetic profiles with different backgrounds and formatting needs.
I use the resume generator for my own job search, and I write my own cover letters by hand. Hand-tailoring each cover letter avoids losing my voice or over-generalizing across different applications.
Grace, a third-party user, adopted the tool during her active job search, addressing a genuine capacity and burnout constraint. This is one external user, not a broadly validated sample, and I onboarded her personally rather than through self-service.
The pipeline's technical capacity extends well beyond how I currently use it. A full application (resume plus cover letter) runs about 12 sequential model calls across both tracks: small structured-extraction calls taking a few seconds each, the larger constraint-heavy writing calls (the cover letter draft in particular) taking longer. Roughly, that's 2 to 4 minutes of API processing time per application, estimated from the call architecture. Paired with bulk import of saved job postings, the practical scale is bounded by how many postings I choose to bring in and how much I want to review or edit. I designed and use it as a selective job-application co-pilot. It doesn't replace hand-tailoring a cover letter to a specific opportunity, building relationships through networking, or the slower work of actually strengthening my position through certifications or projects.
Two friends have expressed interest in using the tool. Finishing self-service onboarding, most of which is already reflected in the self-serve profile agent, would let them set up their own profiles directly. The intent is to offer the tool and support to people who need it. Commercializing it isn't the goal, which is part of why most of the code is public on GitHub.
What I did, what AI did, what I checked
I owned
- The higher-level workflow/architecture (the actual system design)
- Design decisions throughout
- QA
- Prompt engineering
- Debug-pivot decisions: when something broke, deciding whether a durable fix or a quick fix was the right call
- Being the first end user and tuning the system based on real output quality (e.g., recognizing cover-letter generation needed an extensive constraint set to produce a format and voice close enough to be usable)
- Final decision authority on every consequential fork in the build
- Protecting my own voice, declining to let AI draft my personal narrative and instead writing it myself, using AI only for structural feedback
- Scope discipline: deciding what to build now, and what to deliberately leave out (self-onboarding, certain UI polish)
AI-assisted
- Code generation and implementation
- Refactoring and review
- Documentation
- Debugging suggestions
- Infrastructure/deployment execution support (diagnosing DNS and HTTPS issues during the real cloud deployment)
I verified/accepted
- Independently re-checked AI's own verification claims rather than accepting them at face value (caught a real gap in a security sweep this way)
- Caught factual/terminology errors directly (a miscounted model, an invented term)
- Reproduced and confirmed each bug fix live before accepting it as resolved
- Accepted or rejected every proposed design at each fork, rather than deferring to whatever was proposed
What this doesn't prove yet
Self-service onboarding is not yet built. The current biggest constraint is extending the tool use to new users without my direct involvement.
No formal external evaluation study yet. One external user so far, not a broader sample.
The tool won't do certain things, and isn't meant to. It doesn't build a user's network, improve their actual qualifications, or replace the judgment only they have about which opportunities are worth pursuing.
The quality of what it generates depends on the quality of what a user gives it. Thin or vague facts produce thin or vague resumes and cover letters. The self-serve agent exists partly to help sharpen facts, skills, bullets, and stories toward concrete, evidence-backed claims instead of vague trait statements, but it can only work with what's actually there. Users are encouraged to gather their own outside signal, direct feedback specific to their industry, to confirm or challenge whether this approach is actually working for them.
It's built to remove repetitive drafting labor. It was never meant to replace the parts of a job search that require the person doing it.