Settings
What RoleFit is currently wired to. Everything here is read from environment variables, so change .env.local and restart the dev server to see it update.
Services
Database
Hosted Postgres via the neon-http driver
DATABASE_URLOpenRouter
Parsing, OCR, match explanations and embeddings are all live.
OPENROUTER_API_KEYVercel Bloboptional
Not set. CVs are still parsed, but the original file is not kept.
BLOB_READ_WRITE_TOKENLanguage model tasks
Five distinct jobs, each with its own environment variable. Point them at five different models or the same one five times. Slugs on OpenRouter rotate often, so check openrouter.ai/models and filter by Free if you want zero cost.
CV parsing
Once per CV.
Text modelUsing defaultReads raw CV text and returns structured JSON: name, contact details, skills, work history, education, and estimated years of experience.
What to pick: Reliable JSON output and a long context window. This is the model that most affects data quality, so it is the one worth paying for if you only pay for one.
OPENROUTER_MODEL_PARSE=google/gemini-2.5-flash-lite,openai/gpt-4o-miniPrimary google/gemini-2.5-flash-lite, falling back to openai/gpt-4o-mini if it is unavailable or over quota.
OPENROUTER_MODEL_PARSE_TEMPERATURE=0 OPENROUTER_MODEL_PARSE_MAX_TOKENS=4000OCR / scanned documents
Only for scanned or image CVs.
Vision model requiredUsing defaultTranscribes scanned PDFs and photos of printed CVs that carry no text layer. Only runs when normal text extraction comes back nearly empty.
What to pick: Must accept image input. A text-only model here will fail on every scan.
OPENROUTER_MODEL_OCR=google/gemini-2.5-flash-lite,openai/gpt-4o-miniPrimary google/gemini-2.5-flash-lite, falling back to openai/gpt-4o-mini if it is unavailable or over quota.
OPENROUTER_MODEL_OCR_TEMPERATURE=0 OPENROUTER_MODEL_OCR_MAX_TOKENS=8000Match explanation
Once per candidate, per role scored.
Text modelUsing defaultWrites the recruiter-facing narrative for one candidate against one role: strengths, gaps, and a hiring verdict. It never produces the numeric scores, which are computed in code.
What to pick: Decent reasoning over a short prompt. Output is small, so a cheap model is fine here.
OPENROUTER_MODEL_MATCH=google/gemini-2.5-flash-lite,openai/gpt-4o-miniPrimary google/gemini-2.5-flash-lite, falling back to openai/gpt-4o-mini if it is unavailable or over quota.
OPENROUTER_MODEL_MATCH_TEMPERATURE=0.3 OPENROUTER_MODEL_MATCH_MAX_TOKENS=900Candidate summary
Once per CV, only when SUMMARY_SEPARATE_PASS is enabled.
Text modelDisabledWrites a short neutral profile of the candidate for the recruiter. Off by default, because the parsing pass already returns a usable summary. Turn it on with SUMMARY_SEPARATE_PASS=true to get a better one from a dedicated call.
What to pick: Good prose in a few sentences. The cheapest model you have is fine.
OPENROUTER_MODEL_SUMMARY=google/gemini-2.5-flash-lite,openai/gpt-4o-miniPrimary google/gemini-2.5-flash-lite, falling back to openai/gpt-4o-mini if it is unavailable or over quota.
OPENROUTER_MODEL_SUMMARY_TEMPERATURE=0.3 OPENROUTER_MODEL_SUMMARY_MAX_TOKENS=400Embeddings
Once per CV and once per job role.
Embedding model requiredSet by youConverts CVs and job descriptions into vectors so semantic fit can be measured beyond exact keyword overlap.
What to pick: Must be an embedding model, not a chat model. Free options are rare here. If this is unset or failing, the semantic dimension is dropped and its weight is redistributed across skills, experience and education.
OPENROUTER_MODEL_EMBED=openai/text-embedding-3-smallEMBED_DIMENSIONS=1536
What is never sent to a model
The match scores. Skills, experience, education and semantic similarity are all computed in code from your role definitions, so the same CV against the same role always produces the same number. The models only read documents and write prose.