hired

Open source · runs on your laptop · any local model, or Gemini

A tailored CV you can defend in the interview.

Paste a job description. hired tells you if it's worth applying, then builds a one-page CV from bullets you wrote. The model picks. It never writes.

hiredGenerateApplicationsProfile

Posting text

0/10Apply

Five years of React and TypeScript, and the virtualisation work is close to exactly what this team describes.

ReactTypeScriptLarge tablesDesign systemsAccessibilityReact Native

Maya Okafor

Front-End Engineer · React · TypeScript · Design Systems

Experience

  • Virtualised the transactions table so 50,000-row ledgers scroll smoothly, cutting p75 load time by 40%.ledgerline-virtual
  • Rebuilt the invoicing front-end in React and TypeScript, retiring a seven-year-old jQuery codebase.ledgerline-rebuild
  • Brought the invoice editor to WCAG 2.2 AA, fixing 63 accessibility audit findings.ledgerline-a11y
  • Built a 40-component React library in Storybook, adopted by six client projects.northwind-ds

4 ids returned · 0 sentences written

The problem

Most AI CVs read well until someone asks a follow-up.

A typical AI rewrite

Spearheaded a cross-functional initiative that boosted dashboard performance by 300% and drove $2M in new revenue.

  • Spearheaded You were one of three engineers.
  • 300% Nobody measured that.
  • $2M Where would that number come from?

The same work, from your file

Virtualised the transactions table so 50,000-row ledgers scroll smoothly, cutting p75 load time by 40%.

id
ledgerline-virtual
metric
measured · Datadog RUM, four weeks before and after
cannot claim
Led the team. There was a manager.

How it works

Six screens. One evening per posting.

  1. 01

    Write your profile once

    One Markdown file: every project, the bullets you would defend, and what each project cannot claim. You write it. Nothing in it is generated.

    Profile screen: version, project and bullet counts, one blocked bullet to verify, title variants, summaries and skills.
  2. 02

    Paste a posting

    The whole job description, requirements and all, and pick the model that answers. Nothing is saved until you decide to keep it.

    Generate screen with a pasted job description, a model picker set to granite3.3:8b, and a Check fit button.
  3. 03

    Get a verdict first

    The model you picked reads the posting; the score and gaps are counted from your profile in code. Being told to skip a posting is the most useful answer it gives.

    Fit result: 9 out of 10, marked Apply, with the reasoning and one gap.
  4. 04

    Review the page

    Bullets picked from your pool, coverage per requirement, and a live preview of the exact PDF. Regenerate for another pick, or swap any bullet by hand.

    Generated CV: fit 9 of 10, 6 of 6 requirements covered, selected bullets with their ids, a model picker beside Regenerate, and a Letter-size preview.
  5. 05

    Track what you sent

    Every posting you kept, applied to or not, with the CV that went out, what came back, and a daily target to keep you sending.

    Applications: a daily target of three, reply rate, two postings waiting on a reply, a pipeline from saved to offer, and a table of companies with fit and status.
  6. 06

    Open what you sent

    The CV exactly as it went out, which bullet backed each requirement, why it scored what it did, and where it stands. Re-export or download the PDF any time.

    Application detail for Vantage Point: fit 9 of 10, 6 of 6 requirements backed, status Applied, the bullets that were sent, and View PDF and Re-export buttons.

Models point, code decides

The score is counted, not guessed.

Anything your profile can answer is worked out in code: the score, the gaps, which projects make the page, what each bullet covers. Models get the small jobs code cannot do, so one posting gives the same answer every time.

You pick the model

  • granite3.3:8blocal · default
  • qwen2.5:14blocal
  • qwen3:8blocal
  • gemini-3.6-flashcloud

Any model ollama has pulled, or Gemini. The one you pick answers every call for that posting: reading it, the title, the bullets, the sentences. If it can't, the call fails rather than a different model quietly answering, so comparing two means something. Each saved CV records the model that made it.

Code decides

plain Python

Matches every requirement against your profile, counts the score from what is met, lists the gaps, ranks projects by what they add, and reads coverage off the printed page. Swap the model and none of that moves.

Why granite is the default: technologies found, across 8 real postings

granite3.3:8b
90%
qwen2.5:14b
82%
qwen3:8b
78%
Gemini
49%

Local models run at temperature 0, so one posting gives the same answer every time. Before each local call it checks the machine, and declines when the battery is under 30% and unplugged, macOS is throttling, or less than 15% of memory is free.

Why it can't make things up

The model returns ids, not sentences.

The page is assembled from your file after the model answers. Anything it invents has nowhere to go. Hover an id to follow it.

master.md you write this

### Ledgerline App
claim_boundary:
  cannot_claim:
    - Led the team. There was a manager.
    - Any revenue number. Never measured.

bullets:
  - id: ledgerline-virtual
    text: Virtualised the transactions table…
  - id: ledgerline-cache
    text: Moved data fetching to TanStack…
  - id: ledgerline-ai
    status: blocked  # never sent
    text: Built AI-assisted invoice…

The model's answer all it can say

# Which bullets from Ledgerline App?
{
  "bullet_ids": [
    "ledgerline-virtual",
    "ledgerline-cache"
  ]
}
  1. 01

    Ids, not prose

    A model that can only point at sentences can't write a new one. An id that isn't in your file is dropped and flagged, never printed.

  2. 02

    Blocked never leaves

    Blocked bullets are cut from the pool before the call. The model never sees them.

  3. 03

    Checked after

    Plain code checks the printed page for banned words, missing qualifiers and overflow.

Your profile

Grows by the sentence. Never loosens.

Keeping the file current is the part that slips. So you can say what changed, and it turns that into an edit you can read before it lands.

It can add and correct, never loosen. Removing a cannot_claim, clearing a gap or unblocking a bullet stays a hand edit.

Profile Ask tab: a one-line request, the reply, and a five-line diff adding Redux at working level, with a Confirm and save button.Profile History tab: three versions, and the diff restoring v1 would apply.

The small things

Built for the fortieth application, not the first.

A verdict before the work

Score, reasons and gaps before any CV work. Skip a posting with a clear conscience.

Coverage you can read

Every requirement, and the bullet that backs it. The empty ones are the useful ones.

Exactly one page

Measured by the same renderer that prints the PDF. Topped up from your own priorities.

A pipeline, not a spreadsheet

Saved to sent to heard back, a daily target, and a nudge when something has waited ten days.

The exported one-page CV for the fictional Maya Okafor, tailored to a senior front-end posting.

The output

One page. Measured, not hoped.

The renderer prints the page and measures it. A thin page is topped up from your own priority order, one bullet at a time, and stops before it spills onto a second. The PDF is saved next to the posting that produced it.

Format
Letter PDF, Inter
Bullets
Copied from your file
Coverage
Per requirement, gaps included
Saved with
The posting that produced it

Run it

One command. One port. Your machine.

Docker or a local Python setup, and the same hired command either way. hired setup asks for a password and a free Gemini key, andhired starts ollama for you (in Docker, run ollama serve on the host). It listens on 127.0.0.1 only, so nothing else on your network can reach it.

  • Docker
  • or
  • Python 3 · Node 20+ · pnpm
  • plus
  • ollama
Get it on GitHub