Skip to main content
Glama

applyfit

Tailoring a CV by hand for every posting is slow, and pasting your work history into a random chat box leaves you with no record of what you sent. Applyfit keeps the profile, the posting, the fit score, and the drafts as plain files on your machine. A model is called only when you ask for one.

What applyfit does

You keep a profile (skills, roles, salary floor, location rules) and one folder per application. From there the loop is:

  1. add a posting from a file or a URL.

  2. score it from 0 to 100, with must-haves met and missing, nice-to-haves, red flags, and deal-breakers.

  3. tailor a CV that reorders your existing bullets and names the gaps.

  4. letter a short cover letter.

  5. prep an interview sheet: likely questions, STAR prompts tied to real bullets, and questions to ask them.

  6. board a status table (saved, applied, interview, offer, rejected).

The offline score needs no API key. It is a deterministic keyword-overlap baseline: requirement bullets are checked against your skills and the words in your profile, then mixed with salary, remote, and deal-breaker rules. If a deal-breaker in your preferences shows up in the posting, the score is capped at 25. score --llm asks a model for a second opinion and still prints the offline baseline beside it.

tailor, letter, and prep use the model when a key is set. Without a key they write an offline draft that only copies and reorders facts already in the profile. The model prompt tells it to never fabricate experience and to flag gaps instead.

Command

What it writes

applyfit init

.applyfit/profile.yaml

applyfit add <file-or-url>

.applyfit/applications/<id>/posting.md

applyfit score <id>

score.md and score.json

applyfit tailor <id>

cv.md

applyfit letter <id>

letter.md

applyfit prep <id>

prep.md

applyfit status <id> <state>

updates record.json

applyfit board

prints the table

applyfit mcp

MCP stdio server

Related MCP server: resume-coverletter-mcp

Quickstart

From a checkout of this repo, on Python 3.10 or newer:

python -m venv .venv
source .venv/bin/activate
pip install -e .

applyfit init --profile examples/profile.yaml
applyfit add examples/postings/northline-platform.md
applyfit add examples/postings/bramble-mobile.md
applyfit score northline-platform
applyfit score bramble-mobile
applyfit board

Northline is a remote platform role that lines up with the sample profile. Bramble is an on-site mobile contract under the salary floor, with deal-breakers called out in the breakdown. Both scores run offline. No network and no key.

Offline drafts of the other artifacts:

applyfit tailor northline-platform --offline
applyfit letter northline-platform --offline
applyfit prep northline-platform --offline
applyfit status northline-platform applied
applyfit show northline-platform

To use a model, copy the env file, set a real key, and drop --offline:

cp .env.example .env
# edit ATMOROUTER_API_KEY
applyfit score northline-platform --llm
applyfit tailor northline-platform
applyfit letter northline-platform
applyfit prep northline-platform

Each model call prints a cost line on stderr: tokens in, tokens out, and an estimated dollar amount.

Powered by AtmoRouter

A job search is a pile of short calls: one score, one CV, one letter, one prep sheet, then the same four again for the next posting. A pay-per-token cheap AI API gateway fits that pattern. You are not keeping a seat warm on a monthly plan for a handful of paragraphs.

Applyfit's default provider is AtmoRouter, an OpenRouter alternative. The OpenAI-compatible base is https://atmorouter.dev/v1. Set APPLYFIT_API_STYLE=anthropic and the same client calls the Messages API at https://atmorouter.dev/v1/messages. One ar- key reaches the catalog, including the default model atmo/deepseek-v4.1-flash. The base URL, key, and model are all overridable, so any other OpenAI-compatible endpoint works the same way.

After every call, applyfit estimates dollars from a small built-in price table (USD per million tokens). Override a model in .applyfit/pricing.yaml when the catalog moves:

default:
  input: 0.50
  output: 1.50
models:
  atmo/deepseek-v4.1-flash:
    input: 0.15
    output: 0.60

Treat the printed figure as a budget check. Confirm live rates at https://atmorouter.dev/models.

Credit: Applyfit uses AtmoRouter as its default LLM gateway.

Configuration

Environment variables override .env in the current directory. The shell wins over .env.

Variable

Default

Purpose

ATMOROUTER_API_KEY

empty

Bearer key. APPLYFIT_API_KEY and OPENAI_API_KEY are fallbacks.

APPLYFIT_BASE_URL

https://atmorouter.dev/v1

OpenAI-compatible base URL.

APPLYFIT_API_STYLE

openai

openai or anthropic.

APPLYFIT_MODEL

atmo/deepseek-v4.1-flash

Model id sent on every call.

APPLYFIT_HOME

.applyfit

Workspace directory.

APPLYFIT_TIMEOUT

60

HTTP timeout in seconds.

APPLYFIT_PRICE_INPUT_PER_MILLION

table

Override the input price for every model.

APPLYFIT_PRICE_OUTPUT_PER_MILLION

table

Override the output price for every model.

applyfit config prints the resolved base URL, style, model, and a masked key.

Profile shape (also written by applyfit init):

name: Your Name
headline: The work you want
location: City, Country
salary:
  floor: 150000
  currency: USD
  period: year
preferences:
  remote: required          # required, preferred, office-ok, office-only
  locations:
    allow: [Remote, United States]
    deny: []
    strict: false           # when true, an unmatched location line is a red flag
  employment: [full-time]
  deal_breakers:
    - unpaid trial
  red_flags:
    - relocation required
skills:
  - name: Python
    level: expert
    years: 8
    aliases: []
experience:
  - company: Example
    title: Engineer
    start: 2021-04
    end: null
    bullets:
      - A fact you can defend in an interview.

An application folder looks like this:

.applyfit/applications/northline-platform/
  posting.md
  record.json
  score.md
  score.json
  cv.md
  letter.md
  prep.md

record.json stores status, the last score, and every model call's token counts. The files are plain markdown and JSON, so you can diff them. .applyfit/ is gitignored by default so a real profile is not committed by accident. Remove that line if you want the board in git.

Offline score weights, renormalized over the parts the posting actually has:

  • 0.60 must-have coverage

  • 0.10 nice-to-have coverage

  • 0.20 keyword overlap (share of requirement terms that already appear in the profile)

  • 0.10 preferences (each red flag subtracts 0.20 from this part)

Deal-breakers cap the final number at 25. A bullet counts as met when a skill name or alias appears in it, or when at least 60% of its distinctive words appear in the profile.

Using it from Claude Code / Cursor

applyfit mcp speaks MCP over stdio (newline-delimited JSON-RPC, plus Content-Length frames). Tools: add_job, score_job, tailor_cv, draft_letter, prep_interview, list_applications, set_status, show_profile.

Claude Code (.mcp.json) or Cursor (MCP settings):

{
  "mcpServers": {
    "applyfit": {
      "command": "applyfit",
      "args": ["mcp"],
      "env": {
        "APPLYFIT_HOME": "/absolute/path/to/.applyfit",
        "ATMOROUTER_API_KEY": "ar-your-key-here",
        "APPLYFIT_MODEL": "atmo/deepseek-v4.1-flash"
      }
    }
  }
}

Point APPLYFIT_HOME at the workspace you already use from the CLI so the agent and the terminal share one board. Leave the key unset if you only want the offline tools.

Privacy

The profile, postings, scores, and drafts stay in the workspace directory on the machine where you run the command. Offline score, tailor, letter, and prep do not open a network connection. add fetches a URL only when you pass one. LLM commands send the profile fact sheet and the posting text to whatever host APPLYFIT_BASE_URL names, and nothing else. There is no account, no telemetry, and the API key is read from the environment and never written into record.json.

License

MIT. See LICENSE.

Related MCP Connectors

Related MCP Servers

  • F
    license
    Not graded
    quality
    C
    maintenance
    Enables running a job search with Claude Code: parses CV, discovers roles, fetches exact application fields, drafts non-trivial applications (positioning, not autofill), and renders an offline dashboard for review.
    -
  • F
    license
    Not graded
    quality
    A
    maintenance
    Enables Claude Web users to manage their job application workflow by storing profile and resume data, analyzing job descriptions, preparing applications, and tracking progress — all with manual submission and no platform automation.
    1
    -
  • A
    license
    Not graded
    quality
    A
    maintenance
    Enables an AI agent to research industries and companies, track job postings and deadlines from recruiting sites and spreadsheets, match roles against a personal profile, manage application stages, and fill in application forms up to but not including submission. All data stays in a local folder on the user's machine, with reversible actions and confirmation cards for consequential steps.
    MIT