Project № I · Case study

ResumesKit — a living record, tailored on demand

A resume platform for non-technical job seekers. Import an existing CV once, keep it alive through a conversational agent, and generate tailored — never fabricated — versions for specific postings. Built on a hybrid data model where structured columns carry what needs querying and Markdown carries what AI needs to read. In active development; not yet in production.

I.Problem

The resume is a document people rewrite from scratch every time they need one.

Three problems sit on top of each other. Writing a CV from zero is slow and painful; every application wants a slightly different shape; and the record itself decays — a project that mattered in March is forgotten by October, and the next rewrite begins from a thinner memory than the last. The usual tools address the first problem and make the other two worse: a PDF template is a dead artifact the moment it is exported.

I wanted a platform where the resume was not a document at all, but a living record — one the user keeps current through conversation, and one the system can project into a tailored CV whenever a specific posting demands one. The ground truth lives in the database. The PDF is a rendering.

The goal was to stop asking people to remember their own careers from a blank page.

II.Approach

A hybrid data shape, an AI-first editor, a credit-gated generator with a truthfulness guard.

The product settles into three phases — Onboarding, Applications, Maintenance — and a handful of architectural decisions hold them together:

  • Hybrid data model. Each resume section — experiences, education, skills, certifications, projects, publications, honors — is a row with structured columns only for what needs querying or display (company, role, dates) and a Markdown content field for everything else. The structure carries the facts; the Markdown carries the narrative the AI reads and edits.
  • AI-first editing, Markdown as escape hatch. The primary UX is a conversational agent that updates sections through tool calls. A raw Markdown editor is always one click away for users who want it. The chat is the default; the text field is the floor.
  • A parsing pipeline that imports once. Uploaded PDF → ParseResumeJobResumeParseAgent turns the resume into HTML by section → a second agent structures it into database rows → the user reviews. Onboarding is the moment the record comes alive.
  • A generation pipeline that refuses to invent. FetchSourceData → GenerateCv → GuardInstructions → SanitizeCvHtml → SaveGeneration. A dedicated GuardAgent validates inputs and outputs so the model cannot add a credential the user does not have. Credits are debited inside Application::startGeneration() with transactional safety.
  • Specialized agents, structured output. ResumeParseAgent, ResumeStructureAgent, CvGenerationAgent, GuardAgent each own a narrow job with strict schemas — Gemini 2.5 Flash for parsing, Claude Haiku 4.5 for generation, OpenRouter as the provider.

The stack is Laravel 13 on PHP 8.4 with Fortify, Spatie Media Library, and Wayfinder for typed routes; Inertia v3 + React 19 + Tailwind v4 on the front end; Pest 4 with the browser plugin for end-to-end coverage across onboarding, the application wizard, and CV preview.

III.Outcome

Still being built — but the shape is holding.

3
Product phases: Onboarding → Applications → Maintenance
4
Specialized agents, each with a single structured job
0
Fabricated credentials the guard has allowed through

ResumesKit is in active development and has not yet been opened to users. The onboarding pipeline ingests a real PDF and produces structured rows; the resume sections are CRUD-complete behind the conversational agent; the application wizard generates a tailored CV from a pasted posting against a chosen template, debits a credit, and renders a preview. The GuardAgent has refused every attempt so far to put something in a CV that was not in the record.

The part that already feels right is the boundary between the structured columns and the Markdown. The AI does not have to reason about table schemas; the UI does not have to render arbitrary prose as if it were a field. Each half does the work it is good at.

IV.Retrospective

What I have learned so far — knowing the real lessons arrive with users.

The first thing that keeps proving itself is the decision to let the agent be the primary editor. Every time I have been tempted to add a form, the form has been worse than the conversation for the user and more brittle for me to maintain. The Markdown escape hatch is enough for the long tail; the chat handles the head.

The second is the value of narrow agents with strict schemas. CvGenerationAgent does one thing; GuardAgent does one thing; the onboarding agents do one thing each. When something goes wrong, I can point at the agent and the tool call. Monolithic prompts would have hidden the failure in a thousand tokens.

The third, still forming, is about truthfulness as an architectural property rather than a prompt. Asking a model nicely not to lie is not a strategy; routing its output through a validator that has read the record is. The guard is cheap. It pays every day.

The honest caveat: this project has not yet met its users. The lessons above are the ones engineering can teach on its own. The lessons that matter most — what non-technical job seekers actually want from a living record, how they want to be nudged to keep it alive, what a tailored CV needs to look like to earn the next interview — are waiting on the other side of the first real cohort.