# 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. ```bash 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: ```dotenv RESUME_AGENT_USERNAME=your-username RESUME_AGENT_PASSWORD=replace-with-a-long-random-password ``` You can generate a strong password with: ```bash 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: ```dotenv 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`: ```bash uv run resume-agent models ``` ```dotenv 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: ```dotenv 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: ```bash 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: ```bash 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: ```bash 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`](https://github.com/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: ```bash uv run resume-agent profile build ./my-master-resume.pdf ``` Add factual context not captured in the resume: ```bash uv run resume-agent profile build ./resume.docx \ --about-file ./career-notes.md ``` Inspect what the agent believes about you: ```bash uv run resume-agent profile show ``` Tailor from a URL: ```bash uv run resume-agent tailor "https://company.example/jobs/123" ``` Or from a saved/pasted job post: ```bash 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 ```bash uv run --extra dev pytest uv run --extra dev ruff check . ```