See how I turned this pilot project into a real project in my blog: CogniResume Blog](https://bhuwanadhikari.com.np/projects/2026-05-30-cogniresume/)
ZenCV is a Chrome extension that reads the active tab, turns the page HTML into a cleaned job description, and then generates a tailored CV and cover letter inside the popup.
Backend Repo: https://github.com/bhuwanadhikari/ZenCV-server
- Copy the example file and adjust values as needed:
cp .env.example .envSupported variables:
VITE_API_BASE_URL=http://localhost:8000
VITE_AI_MODEL_NAME=gpt-4.1-mini
VITE_FILE_NAME_PREFIX=myThese are build-time values: VITE_API_BASE_URL powers API calls and host permissions, VITE_AI_MODEL_NAME is used for CV generation, and VITE_FILE_NAME_PREFIX sets the default export filename prefix. Rebuild and reload the extension after changing .env.
- Install dependencies:
npm install- Build in watch mode for extension development:
npm run dev-
Open
chrome://extensions, turn on Developer mode, then useLoad unpackedto loaddist/. -
Reload the extension after rebuilds when needed.
If you want to work on the popup UI in a regular browser tab, you can also run:
npm run webThat mode is useful for styling, but Chrome tab APIs are unavailable there, so reading the active page HTML only works in the installed extension.
For a production build:
npm run buildThe production extension is emitted to dist/.
The extension expects a backend that exposes:
POST /api/job-description/processPOST /api/cv/generatePOST /api/cover-letter/generate
By default it points to http://localhost:8000.
- Job Description tab that reads the current page HTML with the Chrome
scriptingAPI and sends it to the backend for processing - CV tab that generates a structured CV from the processed job description, previews it in the popup, and exports it through the browser print dialog
- Cover Letter tab that generates a cover letter, opens a Gmail compose draft, or exports through the browser print dialog
- Settings tab that shows the API base URL and AI model baked in at build time
To add a new CV template:
- Create a new template component file in
src/popup/cv/cv-templates, for exampleCVTemplate7.tsx. - Follow the shape used by an existing template such as
CVTemplate6.tsx. - Register the new template in
cvTemplates.tsxby importing it, adding its ID toCvTemplateId, and appending it to thecvTemplatesarray with a label and description.
You can also ask ChatGPT to draft CVTemplate7.tsx for you. The easiest way is to give it a strong prompt describing the visual style you want and include one existing file, like CVTemplate6.tsx, as the reference example so it preserves the current component structure and prop contract.
Sample prompt:
Create a new React component called CVTemplate7.tsx for this project.
Use CVTemplate6.tsx as the reference for component structure, prop names, typing, and overall conventions. Keep the same input contract so it works with the existing cvTemplates registry.
Design goal:
- Make it visually distinct from the existing templates
- Keep it professional and printable on A4
- Preserve good spacing and readability for long experience sections
- Use the provided cv data only; do not invent new fields
- Respect previewZoom like the existing templates do
Output:
- Return the full contents of CVTemplate7.tsx only
- Keep imports consistent with the current codebase
- Make sure it can be dropped into src/popup/cv/cv-templates and then registered in cvTemplates.tsx
Reference file:
- src/popup/cv/cv-templates/CVTemplate6.tsx
- Open a job posting page in Chrome.
- Open the ZenCV extension popup.
- Review the processed text in the Job Description tab.
- Open the CV tab to preview and export the generated CV.
- Open the Cover Letter tab to preview, print, or open a Gmail compose draft.
- The extension cannot read restricted Chrome pages such as
chrome://*, the Chrome Web Store, or other extension pages - Changing the API origin requires rebuilding so the manifest host permissions stay in sync
- Export uses the browser print flow rather than generating PDF files directly
Open work is tracked in TODO.md.


