pocket-resume

AGENTS.md

This file provides guidance to AI coding agents and human contributors when working on this repository. It is intentionally public so contributors and AI tools can share a common operating manual.

What this repo is

PocketResume is a Chrome Extension (Manifest V3) built with vanilla HTML/CSS/JS. No bundler / build pipeline for app code; the only build step is esbuild for the cloud-sync bundle. Edit source files, reload the unpacked extension in Chrome.

Key runtime entrypoints (declared in manifest.json):

Common commands

Install JS deps

The extension runs without Node at runtime, but the repo uses npm to manage dependencies (and to bundle cloud-sync.js + update the vendored jsPDF build).

npm ci
# or
npm install

Build cloud-sync bundle

src/cloud-sync.js is bundled by esbuild into cloud-sync.js at the repo root (gitignored). Required env vars (CLERK_PUBLISHABLE_KEY, CONVEX_URL) are injected at build time. See .env.example and package.jsonscripts/build-clerk.mjs.

cp .env.example .env.local
# fill in your own Clerk + Convex values
npm run build:clerk

Update vendored jsPDF

popup.html loads jsPDF from libs/jspdf.umd.min.js (vendored). If you bump jspdf, copy the built artifact into libs/.

npm install jspdf@latest
cp node_modules/jspdf/dist/jspdf.umd.min.js libs/jspdf.umd.min.js

Run / debug in Chrome

No dev server.

Debugging:

Convex backend (optional)

npx convex dev

Requires CONVEX_DEPLOYMENT in .env.local. Generated code goes to convex/_generated/ (gitignored).

Tests / lint

None configured. No test runner or linter. Validate by hand: load unpacked, generate a resume with a real API key, inspect the PDF + the service worker console.

High-level architecture

Generation pipeline (main user flow)

  1. User clicks “Generate” in popup (popup.js).
  2. Popup calls chrome.runtime.sendMessage({ type: 'START_GENERATION', payload: { tabId, resumeStyle, resumeId } }).
  3. Background service worker (background.js) handles START_GENERATION:
    • Reads settings from chrome.storage.local (API key per provider, resumes, cover letter toggle).
    • Requests page content from content script via GET_PAGE_CONTENT. Falls back to injecting content.js via chrome.scripting.executeScript(...).
    • Calls the active AI provider:
      • Resume generation as strict JSON text (no markdown fences)
      • If cover letter is enabled, a second call generates the cover letter as strict JSON text
  4. Background replies: { status: 'success', data: <resumeJsonString>, coverLetterData: <coverLetterJsonString|null> }.
  5. Popup:
    • Strips accidental Markdown fences.
    • JSON.parse(...) the model output.
    • Generates / downloads PDFs via jsPDF:
      • PocketResume layouts (basic / professional / faang): generatePDF(...) in popup.js
      • Alternative layouts (jake / deedy / academic-cv): window.ResumeRenderers.generateResumePDF(...) in resume-renderers.js
    • Cover letter: generateCoverLetterPDF(...) in popup.js

Resume refinement flow

  1. User clicks “Refine Resume” on the options page (options.js).
  2. Options sends REFINE_RESUME to background with source text.
  3. Background calls the provider’s *ResumeRefinement(...) function — rewrites source into a cross-style master resume (no job-description tailoring).
  4. Options shows a side-by-side review panel with change summary and warnings.
  5. User can Apply (replaces source text) or Cancel. Undo restores the last pre-refine backup.

Resume JSON extraction flow

  1. User clicks “Extract JSON” on the options page.
  2. Options sends EXTRACT_RESUME_JSON to background with source text.
  3. Background calls the provider’s *ResumeExtraction(...) function — extracts structured JSON profile from raw text.
  4. JSON is saved as jsonContent on the resume entry and persisted. Used as jsonContent in the generation pipeline.

Resume styles & layout mapping

Configured by getResumeStyleConfig(...) in background.js:

UI Style promptStyle layout PDF Renderer
basic basic pocketresume popup.jsgeneratePDF
professional professional pocketresume popup.jsgeneratePDF
faang faang pocketresume popup.jsgeneratePDF
jake faang jake resume-renderers.jsrenderJakeLayout
deedy faang deedy resume-renderers.jsrenderDeedyLayout
academic-cv academic-cv academic-cv resume-renderers.jsrenderAcademicCvLayout

Settings + persistence

Settings are stored in chrome.storage.local, managed in options.js.

Important keys:

Legacy migration: userProfileresumes[0].content

AI provider support

Four providers supported, selected via apiProvider:

Each provider has matching callGemini* / callOpenAI* / callAnthropic* / callOpenRouter* variants for all 4 pipelines: generation, cover letter, extraction, refinement. Naming is historical — the function is selected at runtime based on apiProvider.

Cloud sync (optional feature)

When enabled, resumes sync across devices via Clerk (auth) + Convex (backend).

Architecture:

Credentials are never hardcoded. The build step injects CLERK_PUBLISHABLE_KEY and CONVEX_URL from .env.local into the bundle. Contributors must set up their own Clerk + Convex accounts.

File layout

PocketResume/
├── manifest.json            # Manifest V3 entrypoint wiring
├── background.js            # Service worker: pipeline + AI calls
├── content.js               # Content script: page text extraction
├── popup.html / popup.js    # Popup UI + PocketResume PDF generation
├── options.html / options.js# Settings: API keys, resumes, toggles
├── resume-renderers.js      # Jake / Deedy / Academic CV PDF layouts
├── src/cloud-sync.js        # Cloud sync source (bundled → cloud-sync.js)
├── cloud-sync.js            # [generated, gitignored] esbuild bundle
├── convex/                  # Convex backend
│   ├── auth.config.ts
│   ├── schema.ts
│   ├── resumes.ts
│   └── _generated/          # [generated, gitignored]
├── libs/jspdf.umd.min.js    # Vendored jsPDF
├── scripts/build-clerk.mjs  # Build script for cloud-sync bundle
├── .env.example             # Template for .env.local
├── AGENTS.md                # This file
├── CONTRIBUTING.md
├── CODE_OF_CONDUCT.md
├── SECURITY.md
├── LICENSE
└── package.json             # Build scripts only (no runtime deps)

Where to make common product changes

Coding conventions

Common pitfalls

Privacy posture

PocketResume is privacy-first by default. See privacy-policy.md for the full policy. The Chrome extension: