<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Shaozhe Zhang</title>
    <description>The latest articles on DEV Community by Shaozhe Zhang (@shaozhe_zhang_bce8b810d9c).</description>
    <link>https://dev.to/shaozhe_zhang_bce8b810d9c</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4028845%2F6150bc54-3197-4226-acf0-eedbb6721a33.png</url>
      <title>DEV Community: Shaozhe Zhang</title>
      <link>https://dev.to/shaozhe_zhang_bce8b810d9c</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/shaozhe_zhang_bce8b810d9c"/>
    <language>en</language>
    <item>
      <title>Building an AI Resume Rewriter That Refuses to Invent Achievements</title>
      <dc:creator>Shaozhe Zhang</dc:creator>
      <pubDate>Tue, 14 Jul 2026 13:48:46 +0000</pubDate>
      <link>https://dev.to/shaozhe_zhang_bce8b810d9c/building-an-ai-resume-rewriter-that-refuses-to-invent-achievements-3983</link>
      <guid>https://dev.to/shaozhe_zhang_bce8b810d9c/building-an-ai-resume-rewriter-that-refuses-to-invent-achievements-3983</guid>
      <description>&lt;p&gt;AI is very good at making a resume sound more polished. It is also very good at making an unsupported claim sound completely plausible.&lt;/p&gt;

&lt;p&gt;That tension is what led me to build &lt;a href="https://zesume.xyz/app" rel="noopener noreferrer"&gt;Zesume&lt;/a&gt;, an AI resume rewriter for students and early-career applicants targeting software engineering, quant, finance, and general roles.&lt;/p&gt;

&lt;p&gt;The goal is deliberately narrower than “let AI write your resume.” Zesume starts with an existing resume, improves its structure and language, and tries to preserve a hard boundary:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Rewrite the evidence. Do not manufacture the evidence.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The core rewriter is available without creating an account, so you can try the workflow directly.&lt;/p&gt;

&lt;h2&gt;
  
  
  The problem with plausible improvements
&lt;/h2&gt;

&lt;p&gt;Consider a source bullet like this:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Built a React dashboard for a university project.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;There are many legitimate ways to improve it:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Developed a React dashboard that organized project data into reusable, interactive views.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;But an AI model may be tempted to make the bullet look more impressive:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Developed a React dashboard used by 5,000 students, reducing reporting time by 40%.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The second version sounds stronger, but the user never supplied those numbers. On a resume, that is not a harmless creative flourish. It is a false claim the applicant may later have to defend in an interview.&lt;/p&gt;

&lt;p&gt;This problem becomes especially visible for students. Their experience may be real and technically interesting, but it often lacks the clean metrics found in polished resume examples. A useful rewriting tool should help express the available evidence clearly instead of filling every gap with a synthetic percentage.&lt;/p&gt;

&lt;h2&gt;
  
  
  Treating the current resume as the source of truth
&lt;/h2&gt;

&lt;p&gt;Zesume always treats the pasted or uploaded resume as its primary source. The rewriting instructions explicitly prohibit adding unsupported:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;employers, roles, and internships;&lt;/li&gt;
&lt;li&gt;degrees, grades, awards, and rankings;&lt;/li&gt;
&lt;li&gt;technologies, datasets, and financial instruments;&lt;/li&gt;
&lt;li&gt;percentages, revenue, user counts, latency improvements, and model metrics.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If a useful metric is missing, the preferred behavior is to report it as missing information rather than insert a number.&lt;/p&gt;

&lt;p&gt;A simplified version of the instruction looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Core rule: Rewrite, do not invent.

Preserve the user's original facts.
Do not add companies, roles, technologies, metrics, or achievements.
If a metric is missing, put it in missingInformation.
If a claim is uncertain, keep it conservative and add a warning.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Prompt instructions cannot guarantee factual accuracy on their own. I do not want to pretend otherwise. Zesume still asks the user to review the result before using it.&lt;/p&gt;

&lt;p&gt;The instructions are one layer in a design that also constrains what the model returns and makes uncertainty visible to the user.&lt;/p&gt;

&lt;h2&gt;
  
  
  Separating career direction from resume structure
&lt;/h2&gt;

&lt;p&gt;One early design decision was to avoid treating “template” as a single choice.&lt;/p&gt;

&lt;p&gt;A resume has at least two independent dimensions:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Career direction&lt;/strong&gt; — what evidence should be emphasized?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Document structure&lt;/strong&gt; — how should that evidence be organized?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Zesume therefore lets users select a career target separately from a structure.&lt;/p&gt;

&lt;p&gt;The current career targets are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Software engineering&lt;/li&gt;
&lt;li&gt;Quantitative research and trading&lt;/li&gt;
&lt;li&gt;Finance and spring-week applications&lt;/li&gt;
&lt;li&gt;General internships&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The built-in structures include a classic ATS layout, a project-heavy software engineering layout, a quant research layout, a finance layout, and a one-page student layout.&lt;/p&gt;

&lt;p&gt;This separation matters. A software engineering applicant may want a project-heavy structure, while another applicant with more work experience may prefer a classic chronological layout. Both can still receive software-engineering-specific rewriting guidance.&lt;/p&gt;

&lt;p&gt;Career rules are also conservative in different ways. For example, the quant target explicitly prohibits inventing Sharpe ratios, returns, information coefficients, drawdowns, or backtest performance. If those values are absent, the model can recommend that the user add them, but it should not guess them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why the model returns structured data
&lt;/h2&gt;

&lt;p&gt;The model does not return only a large Markdown string. It produces two synchronized representations:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;professional resume text for reading and copying;&lt;/li&gt;
&lt;li&gt;structured resume data for rendering and document export.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The structured representation contains a header, sections, items, details, bullets, and quality notes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;StructuredResume&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;header&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;location&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;phone&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;links&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[];&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="nl"&gt;sections&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;items&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="nl"&gt;role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="nl"&gt;organization&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="nl"&gt;date&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="nl"&gt;location&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="nl"&gt;details&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[];&lt;/span&gt;
      &lt;span class="nl"&gt;bullets&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[];&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;qualityNotes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;majorChangesMade&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[];&lt;/span&gt;
    &lt;span class="nl"&gt;missingInformation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[];&lt;/span&gt;
    &lt;span class="nl"&gt;warnings&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[];&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This gives the application a contract to validate. The server rejects invalid JSON shapes, limits oversized output, normalizes fields, and renders a text fallback from the structured representation when needed.&lt;/p&gt;

&lt;p&gt;It also gives missing information a real place in the interface. A model no longer needs to “solve” every incomplete bullet. It can say that a result, scale, or metric would strengthen the resume and leave the decision to the user.&lt;/p&gt;

&lt;p&gt;Again, structural validation is not the same as semantic fact-checking. It tells us that the response is safe to process and render; it does not prove that every sentence is supported. That distinction is important when building user-facing AI products.&lt;/p&gt;

&lt;h2&gt;
  
  
  Custom DOCX templates without trusting their example content
&lt;/h2&gt;

&lt;p&gt;Zesume also supports custom TXT and DOCX templates for paid plans.&lt;/p&gt;

&lt;p&gt;This introduced another source-of-truth problem. A template may contain example names, companies, dates, metrics, and achievements. Those examples are useful for understanding layout and writing style, but they must never become candidate facts for the user's resume.&lt;/p&gt;

&lt;p&gt;The template flow therefore extracts a sanitized specification describing things such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;section order;&lt;/li&gt;
&lt;li&gt;density and length expectations;&lt;/li&gt;
&lt;li&gt;bullet style;&lt;/li&gt;
&lt;li&gt;formatting and content rules.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The template is treated as a structure and style guide, not as resume evidence.&lt;/p&gt;

&lt;p&gt;For DOCX export, the browser keeps the original file for the current session. The export process modifies the document content while preserving as much of the template's existing layout as possible. The original uploaded template is not kept as a reusable server-side document library.&lt;/p&gt;

&lt;h2&gt;
  
  
  The current stack
&lt;/h2&gt;

&lt;p&gt;Zesume is a full-stack Next.js application deployed to Cloudflare Workers through OpenNext.&lt;/p&gt;

&lt;p&gt;The main pieces are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Next.js and React&lt;/strong&gt; for the application and route handlers;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cloudflare Workers and OpenNext&lt;/strong&gt; for deployment;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;DeepSeek&lt;/strong&gt; for structured resume rewriting and template analysis;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;PostgreSQL and Prisma&lt;/strong&gt; for accounts, access, saved history, and optional career memory;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Auth.js&lt;/strong&gt; for Google sign-in;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;DOCX and OOXML tooling&lt;/strong&gt; for document extraction and export.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Resume generation uses bounded structured output and a request timeout. Uploaded resume and template files are processed in memory rather than being written to application logs or stored as original files.&lt;/p&gt;

&lt;p&gt;Signed-in users can save selected generations and maintain optional profile or career memory. That memory is supporting context, not an unrestricted second source. The current resume remains primary, and potentially useful missing details should become suggestions rather than silently inserted claims.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the product can do today
&lt;/h2&gt;

&lt;p&gt;The current workflow is:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Paste resume text or upload a TXT/DOCX resume.&lt;/li&gt;
&lt;li&gt;Choose a career target.&lt;/li&gt;
&lt;li&gt;Choose a built-in or eligible custom structure.&lt;/li&gt;
&lt;li&gt;Select a professional, concise, or technical tone.&lt;/li&gt;
&lt;li&gt;Generate and review the rewritten result.&lt;/li&gt;
&lt;li&gt;Export it as TXT or DOCX.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The core workflow works without sign-up. Accounts are used for features such as saved history, profile information, and career memory.&lt;/p&gt;

&lt;h2&gt;
  
  
  What it deliberately does not do yet
&lt;/h2&gt;

&lt;p&gt;The current version does not support:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;PDF import or export;&lt;/li&gt;
&lt;li&gt;a full visual resume editor;&lt;/li&gt;
&lt;li&gt;restoration of arbitrary source formatting;&lt;/li&gt;
&lt;li&gt;every complex DOCX layout;&lt;/li&gt;
&lt;li&gt;automatic verification of every generated claim.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These are not hidden behind optimistic copy. File formats and document layouts become complicated quickly, and resume accuracy is too important to present probabilistic output as verified truth.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I learned
&lt;/h2&gt;

&lt;p&gt;The largest lesson was that adding constraints can make an AI product more useful.&lt;/p&gt;

&lt;p&gt;A resume rewriter does not need unlimited creativity. It needs controlled transformation, visible uncertainty, and a workflow that keeps the user responsible for the final version.&lt;/p&gt;

&lt;p&gt;Structured output helped, but not because JSON magically prevents hallucinations. It helped because the product could represent uncertainty, validate the response shape, and separate content generation from document rendering.&lt;/p&gt;

&lt;p&gt;The second lesson was to keep different sources in different trust categories:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the current resume is evidence;&lt;/li&gt;
&lt;li&gt;user-approved memory is supporting context;&lt;/li&gt;
&lt;li&gt;a template is a structural reference;&lt;/li&gt;
&lt;li&gt;the model is a transformation engine, not an authority on the user's life.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That trust model now influences most implementation decisions in the project.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;

&lt;p&gt;You can try Zesume at &lt;a href="https://zesume.xyz/app" rel="noopener noreferrer"&gt;zesume.xyz/app&lt;/a&gt;. The core rewriting flow does not require an account.&lt;/p&gt;

&lt;p&gt;I am particularly interested in feedback on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;whether the rewritten bullets stay faithful to the source;&lt;/li&gt;
&lt;li&gt;whether missing-information notes are useful;&lt;/li&gt;
&lt;li&gt;how well the career-target and structure choices fit real applications;&lt;/li&gt;
&lt;li&gt;where the DOCX workflow breaks on unusual documents.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you build AI features around user-provided facts, I would also be interested to hear how you separate useful transformation from unsupported invention.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>webdev</category>
      <category>showdev</category>
      <category>nextjs</category>
    </item>
  </channel>
</rss>
