A local tool that reads a job posting, tailors my CV to it, mechanically checks the result for invented claims, and only then sends the application.
The problem
Tailoring a CV per application is slow, and handing the job to a model is how a CV quietly starts claiming Kubernetes. The interesting half of this is not the generation — it is refusing to send anything the master CV cannot support.
ApplyWise running locally in dry-run mode: everything is generated, nothing is sent. Job-posting screenshots are blurred.
Request pathModel
posting · screenshot or text
→vision extraction
→tailor against master facts
→deterministic validator
→PDF render
→send
A tailored CV that adds a technology the master CV does not contain is rejected and regenerated once, not sent.
Role
Sole author
Period
2026
Stack
Next.js 15
TypeScript
Anthropic API
react-pdf
Nodemailer
sharp
Zod
node:test
Status
A personal tool rather than a product. It runs locally against my own CV, that data is gitignored, and there is no public repository or hosted instance.
What I built
A deterministic validator checks every tailored CV against facts extracted from the master CV. It catches added technologies, added numbers, inflated years and structural forgery, and it is biased toward rejection: a false rejection costs one regeneration, an unsupported claim reaches a real employer.
The validator is mechanical rather than an LLM grading its own homework, and its limits are written down in the code — it cannot tell whether a rewrite distorts emphasis while staying inside the source vocabulary.
The technology lexicon deliberately omits names that are also ordinary English — rest, spring, swift, chef, linear — because case-insensitive matching on those rejects truthful CVs.
Job postings are untrusted input, so the model is given explicit rules for handling them and the extracted JSON is isolated before it is parsed.
Application addresses are never guessed or derived from a domain. No address in the posting means the application stops and says so.
Upload limits are shared by client and server so the two cannot drift, and the server re-checks all of them: 30 images, 10 MB each, 100 MB per batch, and a 50-megapixel ceiling that refuses decompression bombs regardless of how small the file is.
Postings process five at a time with every failure caught per application, so one unreadable screenshot never takes down the batch — and dry-run is the default, so sending has to be switched on deliberately.