The Problem with Single-Prompt AI
Every AI resume tool we tried does the same thing: take your resume and a job posting, run it through one big prompt, return a rewritten version. The output is always mediocre.
Why? Because a single prompt is trying to do too many things at once: understand the job, understand your experience, reorganize content, match keywords, assess fit, and format output. Each of these is a distinct cognitive task that benefits from focused attention.
The Hypothesis
What if we broke the problem into specialized agents — each focused on one step — connected by a pipeline with structured contracts between them?
This is the same principle behind microservices, Unix pipes, and assembly lines: specialized components connected by clear interfaces outperform monolithic systems for complex tasks.
Architecture Overview
CV Tailor uses 6 sequential agents orchestrated by a state machine:
Job Posting → [Job Interpreter] → JobBrief
↓
Your Profile → [CV Selector] → Draft CV
↓
[Fit Validator] → FitReport (score + gaps)
↓
score < threshold? → [Interviewer] → Questions
↓
Your Answers → [Facts Updater] → Updated Profile
↓
(loop back to CV Selector)
↓
score >= threshold → [LaTeX Agent] → PDFEach agent is a pure function with Zod-validated input/output schemas. No agent knows about the others — they communicate only through structured data.
Agent 1: Job Interpreter
Input: Raw job posting text (plain text or HTML) Output: Structured JobBrief (Zod-validated JSON)
The Job Interpreter's job is to extract signal from noise. A job posting contains a mix of real requirements, nice-to-haves, company boilerplate, and legal disclaimers. The agent parses this into structured fields: role title, seniority, key requirements, preferred skills, company context, and hiring signals.
The critical insight: extracting implicit requirements is as important as stated ones. "Fast-paced startup environment" implies adaptability and comfort with ambiguity. "Cross-functional collaboration" implies communication skills and stakeholder management.
Agent 2: CV Selector
Input: User's profile facts + JobBrief Output: Tailored CV in Markdown
This agent doesn't rewrite your resume — it selects and reframes. Given your full profile (achievements, projects, skills, context) and the structured job brief, it picks the most relevant experiences and frames them in the language of the target role.
We chose Markdown as the intermediate format because it's human-readable, easy to diff, and cleanly separates content from presentation. The LaTeX formatting happens later.
Agent 3: Fit Validator
Input: Draft CV + JobBrief Output: FitReport — score (0-100) + structured gap list
This is where semantic scoring diverges from keyword matching. Instead of counting keyword overlaps, the Fit Validator evaluates structural alignment:
- Does the CV demonstrate the key competencies the role requires?
- Are there specific gaps where the candidate likely has experience but hasn't mentioned it?
- Is the seniority level appropriate?
Each gap is returned as a structured object with the requirement, what's missing, and why it matters for this role.
Agent 4: Interviewer
Input: FitReport gaps + user profile Output: Targeted questions
This is CV Tailor's most unique feature. When the Fit Validator identifies gaps, the Interviewer generates specific questions designed to surface relevant experience the user forgot to include.
Not "Tell me about your leadership experience" — but "The role requires stakeholder management. You led the payment integration at [Company]. Can you describe a time you presented technical decisions to non-technical leadership during that project?"
The specificity matters. Generic questions get generic answers. Targeted questions unlock real experiences.
Agent 5: Facts Updater
Input: Interview answers + existing profile facts Output: Merged, updated profile facts
The user's answers need to be integrated into their profile without overwriting existing data. This agent handles the merge: adding new facts, enriching existing ones, and maintaining the structural integrity of the profile.
Agent 6: LaTeX Agent
Input: Final CV Markdown Output: LaTeX source + compiled PDF
The last agent converts the Markdown CV into professional LaTeX, then compiles it to PDF using Tectonic. The result has real typographic quality — proper kerning, ligatures, and layout — that HTML-to-PDF converters can't match.
The Iteration Loop
After the Fit Validator scores the draft, the pipeline checks: is the score above threshold (default: 75)? If not, it loops through agents 4-5 (interview + update), then re-runs agents 2-3 (draft + score). This continues until the fit score exceeds the threshold or max iterations (default: 3) are reached.
Each iteration produces a measurably better CV because the profile gets richer with each round of questions.
State Machine Design
The pipeline is orchestrated by a state machine in runner.ts. Each state maps to an agent, and transitions are determined by the agent's output:
INTERPRETING→SELECTING(always)SELECTING→VALIDATING(always)VALIDATING→INTERVIEWING(if score < threshold) orCOMPILING(if score >= threshold)INTERVIEWING→WAITING_FOR_ANSWERS(pause for user input)UPDATING→SELECTING(loop back)COMPILING→DONE
Progress is streamed to the client via Server-Sent Events (SSE), so users see real-time updates as each agent completes.
Structured Output with Zod
Every agent that returns JSON uses Zod schemas as contracts. The LLM call wrapper (llmJsonCall) forces the model to produce valid, schema-conforming output. If the output doesn't parse, the retry mechanism kicks in with the validation error in the prompt.
This eliminates an entire category of bugs: malformed JSON, missing fields, wrong types. The schema IS the contract between agents.
Client-Side-First Architecture
All user data lives in the browser's IndexedDB via Dexie.js. The server is completely stateless — it receives facts and a job posting, processes them through the agent pipeline, and returns results. It never stores, logs, or caches user data.
This wasn't just a privacy decision (though it is a strong privacy guarantee). It eliminated massive architectural complexity: no user table, no auth system, no database migrations, no GDPR compliance headaches. Each browser session owns its own data.
Lessons Learned
1. Clear contracts between agents are everything. Zod schemas aren't just validation — they're the API between agents. When we added a new field to JobBrief, every downstream agent that consumed it got type-checked automatically.
2. The interview loop was the highest-leverage feature. We expected the multi-agent pipeline to be the key differentiator. In practice, the interview step — asking the human for information instead of guessing — produced the largest quality improvement.
3. Client-side storage eliminated more complexity than expected. No auth, no database, no user management, no data retention policies. The simplicity compounded at every layer.
4. LaTeX is fragile but worth it. Tectonic compilation fails on edge cases (unusual characters, deeply nested lists). But the output quality is visibly superior to any HTML-to-PDF approach.
5. Start with structured output from day one. Retrofitting Zod schemas onto agents that were returning free-form text was painful. Structured output should be the default for any multi-agent system.
Try It
CV Tailor is free to use. Paste a job posting, import your CV, and see how 6 agents collaborate to build a tailored version.
Your data never leaves your browser. No account required.