Files
resume-reformer/README.md
T

8.2 KiB

Resume Agent

A local, evidence-backed agent that learns a canonical version of your career history once, then tailors your resume to a job URL or pasted job post without inventing facts.

How it works

  1. Profile: reads your master resume and optional career notes, then extracts a structured profile. Every usable claim receives an evidence ID and source excerpt.
  2. Tailor: analyzes the job, selects and rewrites only supported facts, and produces an ATS-friendly Markdown resume.
  3. Audit: makes a separate LLM pass and runs deterministic checks to reject unknown evidence IDs, unsupported claims, and changed contact information.

The profile is your source of truth. Tailoring may reorder, shorten, or rephrase facts; it must not create experience you do not have.

Setup

You need Python 3.11+ and access to either OpenAI or an OpenAI-compatible API.

uv sync --extra dev
cp .env.example .env

The app loads .env automatically. The default OpenAI model is gpt-5.6-terra; override it with RESUME_AGENT_MODEL or --model.

Configure the single-user login before starting the web app:

RESUME_AGENT_USERNAME=your-username
RESUME_AGENT_PASSWORD=replace-with-a-long-random-password

You can generate a strong password with:

uv run python -c "import secrets; print(secrets.token_urlsafe(32))"

Authentication covers the Signal interface, APIs, downloads, static files, and the bundled Oh My CV editor. The server fails closed with HTTP 503 when either credential is missing or still uses the placeholder value. The login page creates a signed, HttpOnly, SameSite session cookie that expires after 12 hours, and both frontends provide a sign-out button. Oh My CV offline caching is disabled so its app shell cannot bypass the server authentication gate.

Binding to localhost is suitable for personal use. If the app is reachable from another machine, place it behind an HTTPS reverse proxy, set RESUME_AGENT_SECURE_COOKIES=true, and do not expose the plain HTTP port.

For an OpenAI-compatible provider, configure the endpoint without putting credentials in the repository:

RESUME_AGENT_API_KEY=your-rotated-token
RESUME_AGENT_BASE_URL=https://service.nokod.ir/v1
RESUME_AGENT_API_STYLE=chat
RESUME_AGENT_LLM_TIMEOUT_SECONDS=1800

Discover the provider's exact model IDs, then add your choice to .env:

uv run resume-agent models
RESUME_AGENT_MODEL=the-model-id-you-selected

Custom endpoints default to the Chat Completions API because it is more widely implemented by OpenAI-compatible services. Set RESUME_AGENT_API_STYLE=responses only when the provider supports the Responses API and structured outputs.

Model calls are logged to stdout with a query ID, endpoint, model, API style, schema, timing, prompt, input, parsed response, and full exception traceback. API keys are never logged. Because prompts contain resume data, disable payload and response bodies while keeping request metadata and errors with:

RESUME_AGENT_LOG_MODEL_PAYLOADS=false

RESUME_AGENT_LLM_TIMEOUT_SECONDS controls the provider read/write timeout. It defaults to 1800 seconds (30 minutes), while connection establishment is capped at 30 seconds. An upstream gateway may still enforce its own shorter timeout.

Usage

Web interface

Launch the local frontend:

uv run resume-agent editor-build
uv run resume-agent serve

Then open http://127.0.0.1:8000. Open /cv/ (or click Open CV editor) for the bundled Oh My CV Markdown editor. Its AI Tailor with Signal tool can learn the current editor buffer, tailor it to a job URL or pasted description, apply the audited Markdown directly, and restore the pre-AI version with one click.

Docker Compose

After configuring .env, build and start the complete app with:

docker compose up --build

Open http://127.0.0.1:8900. The image builds Oh My CV and serves it from /cv/ through the same FastAPI process. Career-profile state and generated resumes persist in the host's .resume-agent/ and output/ directories.

To use another host port, set RESUME_AGENT_PORT when starting Compose:

RESUME_AGENT_PORT=8080 docker compose up --build

Stop the service with docker compose down. This leaves the persisted profile and outputs intact.

Both frontends include a Tailoring strength slider. At 0, the agent stays close to the source wording and organization. At 100, it uses the fullest supported detail and strongest truthful job alignment. The slider never relaxes evidence validation; unsupported requirements remain gaps or follow-up questions rather than resume claims.

Below the slider, Tailoring configuration can switch between:

  • Strict source evidence: every candidate-facing claim must map to one or more evidence IDs extracted from the source resume.
  • Flexible profile-based rewrite: the complete profile and original resume remain the factual source, but claim-level evidence IDs are optional. This mode still tells the model not to invent employers, dates, skills, metrics, or achievements.

Use the Evidence guard control in Signal's header or the Oh My CV AI dialog to disable claim-level evidence enforcement across the entire app. The setting is persisted in .resume-agent/settings.json and applies to tailoring and revision chat. Turning it off forces flexible profile mode everywhere; the supplied-profile truth and no-invention rules remain active.

After tailoring in the main Signal interface, use Open in Oh My CV to create a new local Oh My CV resume from the optimized Markdown and open it directly in the editor.

The tailored-results section also includes a revision chatbot. It can change tone, emphasis, detail, ordering, and length, then refreshes the preview, match assessment, honest gaps, downloads, and Oh My CV handoff. Every revision runs through the same profile-evidence validation and factuality audit as the initial tailoring pass.

Long-running frontend actions use background tasks rather than holding one HTTP request open. Profile extraction, tailoring, Oh My CV tailoring, and revision chat return a task ID immediately; both frontends poll /api/tasks/{task_id} until the model work succeeds or fails. Temporary polling connection errors are retried without cancelling model work.

The main browser interface supports resume upload, career-profile review, job URLs or pasted descriptions, evidence-linked resume preview, match analysis, and Markdown/JSON downloads. API credentials stay in the server environment and are never returned to the browser.

Oh My CV is vendored from Renovamen/oh-my-cv at the commit recorded in vendor/README.md. It is GPL-3.0 licensed; preserve its license and source availability if you distribute the combined application.

Command line

Build your reusable profile:

uv run resume-agent profile build ./my-master-resume.pdf

Add factual context not captured in the resume:

uv run resume-agent profile build ./resume.docx \
  --about-file ./career-notes.md

Inspect what the agent believes about you:

uv run resume-agent profile show

Tailor from a URL:

uv run resume-agent tailor "https://company.example/jobs/123"

Or from a saved/pasted job post:

uv run resume-agent tailor ./job-post.txt
uv run resume-agent tailor "Paste the complete job description here..."

Outputs are written to output/:

  • resume.md: clean tailored resume
  • resume-audited.md: internal audit copy with evidence IDs in invisible HTML comments
  • report.md: matches, real gaps, changes, and questions
  • tailoring.json: complete structured result

Candidate-facing Markdown and Oh My CV PDF output never display evidence references such as [F013]; those IDs remain available only in internal audit data.

Privacy and safety

  • Resume and profile files remain local, but their text is sent to the configured OpenAI API when you run profile build or tailor.
  • Job URLs are restricted to public HTTP(S) addresses and response size is capped.
  • Web-page instructions are treated as untrusted text, not agent instructions.
  • Keep .resume-agent/, .env, and generated outputs out of version control.

Development

uv run --extra dev pytest
uv run --extra dev ruff check .