Skip to content

How matching works

feder-cr edited this page Nov 5, 2026 · 4 revisions

How matching works

Matching happens in four steps: a title search over the job database, a first reading of the best titles, a second reading of the best of those, and a score for each shortlisted posting. Nothing is applied for until you select a job and say yes.

The search plan

When you give AIHawk a resume, it reads the CV and writes a search plan into ~/.aihawk/aihawk.yaml. The plan is under filters.plan, and it is a graph:

  • A node is one facet of the job you want, such as the role or a main skill. It has an id, a weight (how telling it is), and forms.
  • A form is a wording a job title can hold, such as Python Developer, with its own weight for how surely that wording means this job.
  • An arc scales a whole title, or one node of it, when a condition holds. It says when a node id or a phrase is in the title, or unless it is, and then what to multiply: target is a node id or * for the whole title, and multiplier is below 1 to demote or above 1 to promote.

The resume step asks for two to five nodes, four to fifteen forms each, and at most three arcs. An arc is there to guard against a neighbouring trade that shares words with yours. For a chef, for example, an arc can demote a DevOps posting that names "Chef", the configuration tool.

To change what it looks for, where, and what to leave out, press e. For the weights and arcs, change the values in filters.plan and restart aihawk. A form is matched as a whole word, without regard to case, in the title only. Node ids are also listed in filters.include, as the resume step writes them. If the plan has no nodes, each word of filters.include becomes a node of weight 1. Words in filters.exclude drop every title that holds them.

filters:
  plan:
    nodes:
      - id: role
        weight: 1
        forms:
          - {text: Chef, weight: 1}
          - {text: Sous Chef, weight: 1}
      - id: pastry
        weight: 1.5
        forms:
          - {text: Pastry, weight: 1}
    arcs:
      - when: DevOps
        unless: ""
        then:
          - {target: "*", multiplier: 0.2}

Title search

The database holds postings from public job sources, with their titles, companies and places. A posting is found when its title holds one of the plan's forms. Each node scores the title by the best of its wordings that the title holds, and a wording counts for more when fewer postings in your places use it: Python tells more than Engineer. Arcs then scale the title, and a city you live in adds to it. The same title at the same company, posted once per place, is kept once, in its best place. Postings older than 60 days are left out unless max_age_days says otherwise.

Each new posting is given a title score. The next 100 by that score, the best titles, are the batch for the next step.

Jev on the best 100

The decision model (decision_model, typesafe/jev-1.14 by default, through OrcaRouter) reads the batch. For each posting it answers six closed questions about the CV and the posting: the role fits the goals, every requirement the posting states is in the CV, the posting asks for something the CV does not show, the seniority matches, the job is near your places, and the job is far from them. Each answer is a probability that Jev gives for that question. Only answers far enough from even count; the others count for nothing. The counted answers are then signed by their question, and summed.

The final order of the batch is each title's score, standardised across the batch, plus that evidence. The best 25 are shortlisted. The rest are passed over: they stay in the store and are listed below the judged ones. If the decision model cannot read a posting, that posting is ranked by its title alone, and the log says so.

The chat model on the best 25

The judge model (judge_model, deepseek/deepseek-v4.1-flash by default) reads each shortlisted posting, with its description when the database has one, and answers closed questions about it and your CV. The score starts at the middle, 2.5, and each answer moves it up or down by an amount set for that question. A location answer of "no" gives 1 outright. The score is kept between 1 and 5.

A posting without a description is judged on its title and location alone. The judge is told that in that case the requirements and the seniority are "unclear".

The score is advice. Whether to apply is your choice: you select the jobs, and nothing is sent without one yes.

Clone this wiki locally