In the last couple of months, two different people asked if I could share my Japanese-style resume rather than my English one. They wanted the 履歴書 and 職務経歴書, the formats Japanese companies actually ask for when you apply.
Both times, I gave the same awkward answer: “let me get back to you on that.”
My English resume looked decent. I had only a pile of half-finished notes for the Japanese one, already out of date the moment I touched the English version. I would not rewrite both by hand every job cycle in a second language.
So I built JPResume, a small Swift CLI that turns a western-style resume into both Japanese formats and keeps them in sync.
Why a Japanese Resume Requires Different Work
If you have only written western resumes, you might treat the Japanese versions as a translation job. Translation alone does not solve the problem.
A 履歴書 (rirekisho) uses a grid form: name, furigana, photo slot, education and work history with year/month columns, licenses, 志望動機, and 本人希望記入欄. Conventions govern how to mark your current role, end the work history section with 「現在に至る」, and choose western years or Japanese era dates. Some companies care about these details. Some do not. Nothing makes them obvious the first time.
A 職務経歴書 (shokumukeirekisho) provides the free-form counterpart. The actual career story lives here: 職務要約, role details, skills, achievements, and 自己PR. Writing in those phrasing conventions takes its own skill. “Helped increase sign-ups by about 30%” reads naturally in English. In Japanese, something like 新規会員登録数の約30%増加に寄与 fits better.
The two formats also create an alignment problem. Your English and Japanese resumes need to tell the same story, with the same dates, titles, and emphasis. When they drift, you usually notice at the worst possible moment.
A tool can help keep those versions aligned.
How It Works
I kept the pipeline boring on purpose: deterministic where possible, LLM-assisted where useful, and reviewable in between.
flowchart LR
parse[Parse]
normalize["Normalize (LLM)"]
repair[Repair]
validate[Validate]
generate["Generate (LLM)"]
render[Render]
parse --> normalize --> repair --> validate --> generate --> render
Parse stays deterministic. It accepts markdown, DOCX, or PDF and produces a rough structured version. Markdown goes through a parser. DOCX and PDF go through text preprocessing, because once text comes out of those formats, most of the structure disappears. Scanned PDFs fall back to Vision OCR.
The LLM first appears during Normalize. It combines the parsed resume with the Japan-specific facts in jpresume_config.yaml, including the kanji name, furigana, address, education, and certifications, then produces a normalized structure. Dates become real integers. The stage classifies bullets as achievements or responsibilities and groups skills into categories. The prompt explicitly tells the model not to invent anything and asks it to flag ambiguous dates with low confidence rather than guess.
Repair returns to deterministic processing. It sorts roles, reconciles overlapping dates, and fixes is_current inconsistencies. Validate surfaces what remains: overlaps, low-confidence entries, suspicious gaps, or total years that look off.
Generate produces the rirekisho and shokumukeirekisho JSON. Render turns those into markdown and native PDFs using CoreGraphics and Hiragino Sans, so the Japanese typography looks intentional instead of falling back to an awkward default.
If you have built AI-assisted tooling, this pipeline will look familiar: keep control where you can, use the model where it helps, and put a human-readable artifact between stages.
The Workflow I Actually Use
The CLI can run end to end:
jpresume convert resume.md --provider claude-cli --format both
That works. But for most changes, I use the agent skill because it supports the workflow I wanted: external mode.
In external mode, the LLM stages do not call a provider directly. They write a prompt bundle to disk and exit. An agent such as Claude Code, Cursor, or Codex reads the bundle, produces the response JSON, writes it back, and re-runs the stage with --ingest.
In other words, the agent supplies the model output.
That sounds like an implementation detail, but it changes the experience. The agent sees every prompt and every response. It can pause, ask me a question, fix a bad field, and re-ingest without restarting the whole pipeline. When it normalizes a role, I can see exactly how it interpreted the dates before anything downstream depends on them. If something looks wrong, I can edit the JSON instead of running a full re-prompt.
I probably would have gotten this wrong in a one-shot tool. One-shot generation works for a first draft. For a document I might send to a company, I need the review loop.
The Honest Limits
So far, I have tested JPResume on only one resume: mine.
That resume has a specific shape. One country of origin. A software engineering career. Company names that Japanese recruiters likely recognize. Relatively clean dates. A JLPT certification that maps neatly to standard phrasing. It does not cover every edge case: career switches, international graduate programs, long intentional gaps, unusual role titles, or industries where Japanese resume conventions differ from tech.
I would not be surprised if the first outside resume exposes something the normalizer handles poorly, or a phrasing pattern the generator does not produce gracefully. I designed the pipeline to make those fixes cheap: edit an artifact and re-run one stage. I have not seen those cases yet. My sample size is one.
So if you try it and something looks wrong, or you know a resume shape it should handle better, I would like to hear about it. I welcome issues, pull requests, or notes. The README contains the install instructions and agent skill.
What I Would Keep Even If the Tool Changes
I expect the pipeline shape to outlast this implementation: deterministic parsing, strict no-invention normalization, a deliberate validation pause, and external mode so an agent can act as the model while still reviewing its own output.
That pattern works beyond Japanese resumes. It fits any document where a fabricated field costs too much and a fully automated one-shot does not fit: regulatory filings, contracts, internal reports, anything with structure and consequences.
For now, JPResume turns a markdown resume into a 履歴書 and 職務経歴書 that I would actually hand to a company.
Now I have one source to update before the next time someone asks me for both documents.