Skip to content

Configuration

At the end you will know every knob and secret job-pilot reads, and where each one lives.

Three files, one rule: tunables in YAML, secrets in .env (GitHub Actions secrets in CI). Never put a secret in a YAML file — the repo is public.

config.yaml — pipeline knobs

Key Meaning Default
parquet.url_template where the public snapshots live ({ref} = main or a trends/YYYYMMDD tag) GitHub raw URL
filter.categories job categories allowed through Engineering & Tech, Product, Sales & GTM
filter.us_only drop known non-US locations before the paid call; "Remote" and other ambiguous values stay eligible, and dropped jobs still show in the digest table true
filter.targets_config path to job-scout's config.yaml — the single source for title keywords and the salary floor ../job-scout/config.yaml
resumes.dir where the synced resume DOCX files live ./inputs/resumes
resumes.fallback the variant scored and attached when no title rule matches master
resumes.rules ordered variant + title_contains rules; first match wins (case-insensitive substring) eng-manager, genai-fde, data-genai-fde
matcher.pdf_band_threshold attach cover letters and the chosen resume variant from this match band up good_match
matcher.max_jobs_per_run above this, the run skips the paid match step (not aborts — see MAX_JOBS_PER_RUN below) and reports it in the digest 25
email.subject_template subject line with {date} {new} {candidates} {matched} {strong} {pdfs} {resumes} placeholders; a typo renders empty, never blocks the send counts-first template

| jev.* | Jev gate: API URL, model, timeout, retries, breaker, confidence thresholds, near-miss floor, question text | see Jev gate |

Target roles and the salary floor are not duplicated here — edit them once in job-scout's config.yaml and both agents follow.

templates/letterhead.yaml — the cover-letter letterhead

Name, title line, contact fields, links, and colors for the PDF header and signature. Edit it and every letter follows; no code change. The phone number is deliberately empty in the committed file — it arrives via the LETTERHEAD_PHONE secret at run time.

inputs/resumes/ — the resumes

Four DOCX files: master, genai-fde, data-genai-fde, eng-manager. They are the single source of truth: the master is what gets scored (job-pilot extracts its text, tables included) and each matched job's email carries the variant its title selects. The repo is public, so the committed copies have the phone number replaced by {{PHONE}}; the real one is injected from LETTERHEAD_PHONE when an attachment is rendered.

Update them whenever the owner's resume-variant skill cuts a new version:

python tools/sync_resumes.py <resume-variant>/references/master
git add inputs/resumes && git commit && git push   # rebuilds the image

The tool scrubs the phone and refuses to write a file if it finds anything phone-shaped left. tests/test_resumes.py fails the build if a phone number ever reaches a committed resume.

.env / GitHub secrets

Variable Purpose
JOBMATCH_API_BASE, JOBMATCH_AGENT_BASE deployed job-matcher endpoints
SMTP_HOST, SMTP_PORT, SMTP_USER, SMTP_PASS Gmail SMTP (app password)
DIGEST_TO, DIGEST_FROM email addresses; DIGEST_TO accepts a comma-separated list (a@x.com, b@y.com)
RUN_PAID_MATCH paid-call switch — 1 allows /analyze calls; unset/not 1 hard-aborts the run
MAX_JOBS_PER_RUN optional, one-run override of matcher.max_jobs_per_run — e.g. a manual catch-up dispatch (job-pilot.yml's max_jobs_per_run input) after a coverage-expansion burst day skipped matching
LETTERHEAD_PHONE phone for the PDF letterhead
JEV_MODE off (default), shadow or enforce; see Jev gate. In CI it is the repository variable of the same name
TYPESAFE_API_KEY TypeSafe Jev key; without it the gate is off
LANGSMITH_TRACING, LANGSMITH_API_KEY, LANGSMITH_PROJECT LangSmith tracing (optional)
OTEL_EXPORTER_OTLP_ENDPOINT, OTEL_EXPORTER_OTLP_HEADERS OpenObserve span export (optional)
PHOENIX_COLLECTOR_ENDPOINT, PHOENIX_CLIENT_HEADERS Arize (cloud otlp.arize.com or local Phoenix) (optional)

All observability values are optional: when one is missing, the run logs a warning and continues — the email always comes first.

Next: Runbook