# career-ops: the job filter that stops at the Submit button

> An MIT-licensed agent that runs inside an AI coding CLI, scores each listing against your CV on a one to five scale, and drafts an application you are expected to send yourself. The install is one npx command; the first launch is a chat interview.

**santifer/career-ops** — career-ops turns AI coding CLIs such as Claude Code into a job-search command center, scanning job portals, scoring listings on an A-F rubric, and tailoring CVs.

- Repository: https://github.com/santifer/career-ops
- Website: https://career-ops.org
- Stars: 72,920 · Forks: 13,714
- Language: JavaScript
- License: MIT
- Published: 2026-08-04 · Updated: 2026-08-18 · Language: en
- Canonical page: https://hysenlabs.com/projects/santifer-career-ops

## init asks who you are before it reads a single listing

Installation is one command, and the first launch is a conversation rather than a config file. On first launch it asks for your CV, what you want and what you refuse, in chat, and the project frames that as a recruiter's first week. Nothing is configured by hand. That ordering shapes everything after it, because every later judgement is a comparison against the profile you gave in that first session, so an underspecified answer produces confident wrong skips rather than obvious failures. The project is candid that the first runs are rough precisely because the tool does not know you yet. The unit of work is deliberately small: paste one job you were about to apply to tonight, and the expected result is a yes or no on whether that night was worth spending, not a search pipeline run on your behalf.

## The rubric is called A-F in one place and A-H in another

Scoring is the core output, and the repository describes it two different ways. The project description frames the evaluation as a structured A-F rubric resolved into a 1.0 to 5.0 score. The package.json at version 1.34.0 describes the same step as a structured A-H report with a 1-5 score. The feature list in the README never enumerates the grade letters, so neither description is confirmed by the prose. For a reader this is not cosmetic. If you are comparing two shortlisted jobs you need the grade to mean the same thing in both reports, and the metadata will not tell you which set to expect. Open a real generated report and read the grade legend before you trust a skip. The number is between one and five under either description; it is the letters attached to it that differ.

## prepare-application.mjs drafts every field and never POSTs

The refusal to send anything is specific and checkable rather than a promise in a manifesto. Drafting lives in prepare-application.mjs, and the project states plainly that the script never POSTs: it fills in an answer for every field and leaves the submission to you.

```bash
npx @santifer/career-ops init
```

There is no mail transport anywhere in the codebase either, so the note drafted for a contact cannot leave the machine. There is also no telemetry and no backend belonging to the project, which is what keeps applications local. Read together, those three constraints define the entire product boundary: the tool does everything up to the irreversible action and nothing after it. The consequence for a job seeker is that the last thirty seconds of an application, the part where a wrong field or a typo earns a rejection, is the part this project cannot help with at all.

## A weak fit is a skip you can override, not a verdict you cannot

Two of the documented behaviours are a refusal and an escape hatch. When a listing scores badly against your real CV, the tool tells you to skip a weak fit, and you can override that call. After a run of noes it names the gap, which turns a batch of rejections into one concrete thing to learn. Finding someone to talk to is handled the same way: it locates the person and drafts the note, then stops. That is the design in a single sentence. The risk to watch is the override running the other way. A one to five score produced by a model reading a CV against a job description is a model output rather than a measurement, and a profile written in a hurry during the first launch will generate confident skips that do not deserve trust. Override the first few.

## SerpApi sponsors the project and is excluded from the ranking

Scanning depends on a search backend, and that backend is also the project's sponsor. SerpApi is the named sponsor, described as giving developers structured JSON and Markdown from search, maps and shopping engines through a simple API call. The project draws the boundary in writing: sponsorship buys clearly labeled visibility, never influence, no amount of money changes the roadmap or places anything in the product, and sponsors never appear in evaluations, rankings or recommendations. That is a policy statement rather than something the code enforces, and the distinction matters to anyone reading a recommendation as a signal. The consequence is that the funding source and the ranking source are the same company, held apart by a written rule instead of by architecture, so a disclosed sponsorship is the thing to look for rather than an assumption that the two are already separate.

## Local means your machine, not a free model in the cloud

Running locally does not mean running keyless. The documented setup copies an example environment file and fills in values, and the free path still needs an account somewhere.

```bash
cp .env.example .env
```

Gemini is the default route, with a rate-limited free tier on gemini-3.6-flash and gemini-3.5-flash plus gemini-2.5-pro listed as alternatives. OpenRouter is offered with a free tier of hundreds of models at zero cost, and CAREER_OPS_MODEL pins one model instead of using rotation. A third path evaluates through any OpenAI-compatible endpoint, which is the only route to a genuinely local model: the example file names LM Studio, llama.cpp, vLLM and Ollama on the /v1 path. So the accurate version of the local claim is that your CV never reaches the project, not that your CV never leaves your machine.

## The container exists because Chromium will not install everywhere

The Docker path is not packaging convenience, it is a workaround for a named host failure. The image is built on the Playwright base at version 1.63.0 jammy with Chromium already present, because the browser ships inside the image and runs under the image's userland instead of the host's. The compose file keeps a long-running shell so that exec is instant, gives the container one gigabyte of shared memory for Chromium, and holds node_modules in a named volume to avoid a host and container mismatch. It also records which host caused the problem: Ubuntu 26.04, where Playwright will not install. Two release trains also run in parallel, web v0.12.0 and career-ops v1.34.0, both tagged on 2026-09-24, with the last push on 2026-09-27, so any version reference has to say which train you mean.

## Conclusion

Adopt career-ops if your bottleneck is volume rather than wording, and put one of the free API keys in place before judging it, because scanning depends on a search backend the project sponsors. Do not adopt it expecting an application sender: the code states the script never POSTs and that no mail transport exists anywhere in the codebase, so the final click is yours and stays yours. The first thing to verify is the grade set in a real report, since the repository description calls it A-F and package.json calls it A-H.

## FAQ

### How does career-ops decide whether a job is worth applying to?

You paste a job description. It checks that the posting is still live, scores the role against your real CV to decide whether the fit is worth the night, and then drafts the CV, the cover letter and the answers. You read them and you send them.

### How do you install career-ops?

Through npx, run in the AI coding CLI you already use, such as Claude Code, Codex, OpenCode or Antigravity. On first launch it asks about your CV, what you want and what you refuse, in chat, so there is nothing to configure by hand.

### Does career-ops need a paid API key to run?

Not necessarily. The project points to free and local models, and the example environment file documents a rate-limited free tier on Gemini plus an OpenRouter free tier with hundreds of models at zero cost. A local route exists through any OpenAI-compatible endpoint.

### What is career-ops, in short?

An MIT-licensed open source job search agent that scans job portals, evaluates listings into a structured report with a one to five score, tailors your CV and tracks applications. It runs locally inside an AI coding CLI, and the project is free for candidates.

## Sources

- [Official documentation](https://career-ops.org)
- [Official README](https://github.com/santifer/career-ops#readme)
- [Project repository](https://github.com/santifer/career-ops)
- [Release notes](https://github.com/santifer/career-ops/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/santifer-career-ops
