# Jev job filtering

Use Jev to evaluate job descriptions and let code produce a shortlist. The workflow runs locally or on your server using your TypeSafe account. TrueFetch collection is in development, so start with a job JSON file you already have.

## Get the files

- [Python workflow](/examples/jev-job-filter/filter_jobs.py) — complete validation, evaluation and routing.
- [Sample input](/examples/jev-job-filter/jobs.json) — three fictional records.
- [TypeScript API example](/examples/jev-job-filter/evaluate.ts) — one prepared request using Node 24+.
- [Full run instructions](/examples/jev-job-filter/README.md) — input limits, output fields and failure handling.

Save them in one folder. Python 3.11+ needs no additional dependencies.

## Prepare your data

```sh
python filter_jobs.py prepare jobs.json --output requests.jsonl
```

This validates input and writes the exact requests without calling Jev. Supply `title`, `sourceUrl` and `description` for each job. `location` provides work-arrangement context. Missing descriptions go to review. The file accepts 1–25 records; a collection envelope with `status: "partial"` requires `--allow-partial`.

## Call Jev

Set `TYPESAFE_API_KEY` in your process environment using your secret manager, then run:

```sh
python filter_jobs.py run jobs.json --output decisions.jsonl --target-role "Python backend engineer" --work-mode remote
```

The four questions share one request per eligible listing. The script pins `jev-1.13.0` and records the returned model version. Calls consume your TypeSafe allowance, separately from TrueFetch credits. Never expose the key in browser JavaScript.

For a minimal TypeScript call using the prepared file:

```sh
node evaluate.ts requests.jsonl answer.json
```

This evaluates the first eligible request only and saves raw answers. The Python command provides the complete filtering workflow.

## Routing rules

| Check | Decision |
| --- | --- |
| Possible evaluator instructions in the job text: Noul ≥ 0.2 | Review |
| Evidence of actual duties: Noul < 0.8 | Review |
| Role confidence < 0.8 | Review |
| Role score ≤ 0.5 on a 0–3 scale | Skip |
| Requested work arrangement is unknown or confidence < 0.8 | Review |
| Clear mismatch with requested work arrangement | Skip |
| Role score ≥ 2.5, with earlier checks passed | Shortlist |
| Any remaining case | Review |

Rules run from top to bottom. `--work-mode any` bypasses the arrangement check. Thresholds live in `THRESHOLDS` near the top of the Python file. They are starting values to evaluate against labeled examples from your own sources. Confidence is a statistic of the model's distribution, not an accuracy guarantee.

Remote status does not establish country, visa or timezone eligibility. Those restrictions need additional checks. This workflow filters listings; it does not assess people applying for work.

## Trace results and handle failures

Each output row retains its source URL and collection status. Successful evaluations include answers, probabilities, thresholds, model, request ID when available, and token usage. Missing usage remains unknown. Read the source before acting on an uncertain result.

Malformed provider output goes to review and causes exit code 2. Configuration or input errors return 1. Existing output files are never overwritten. A failed run can leave completed rows, so avoid resubmitting them automatically. Retries are bounded to 429 and 529; timeouts are not automatically replayed.

## Model limits

Jev takes text, not images, audio or video. Keep state focused. Perform arithmetic, exact date comparisons and URL handling in code. The model can be influenced by adversarial content; the injection question helps route suspicious text but cannot guarantee detection.

See the [TypeSafe API reference](https://docs.typesafe.ai/api), [confidence guide](https://docs.typesafe.ai/confidence), [model limits](https://docs.typesafe.ai/models) and [known Jev limitations](https://docs.typesafe.ai/model-jaggedness/jev-1.13). Continue with the [worked tutorial](/blog/filter-job-listings-with-jev/) or the [Job Scraper contract](/docs/job-scraper/).
