Hiring Without Trusting Your Gut: The Tool We Built for Our Interviews

Company profile, candidate profile, structured interview, and weighted ranking, all in one small application

Published: 8 min read

View the source code ↗

Hiring means comparing people you meet days apart, on the strength of notes jotted down on the fly and an impression that fades fast. By the end of a run of interviews, the first candidate is already a blur, the notes are scattered between a notebook and a file, and the decision ends up tilting toward whoever you saw last or liked most. That is exactly the problem we set out to avoid when hiring our junior developer in Tallinn.

Rather than keep our notes in a spreadsheet, we built a small web application to run the process. It gathers in one place what used to be scattered: the role profile, the candidate profile, note-taking during the interview, the numerical scoring, and, at the end, a weighted ranking that makes the comparison explicit. This article describes what it does and how it is designed. It is a tool we built for our own use, and we open its code on GitHub: nothing stops you from running it on your own machine.

The Context Always in View

The application follows the real hierarchy of a hiring process: a company, roles, and for each role its candidates. That cascade stays visible in the sidebar, so you always know where you are without having to retrace your steps.

The company profile is defined once and serves every role. You paste a web address or some text, and the application produces a clean overview that you can then refine. Each role works the same way: a job description, imported from a posting or written by hand, and above all selection criteria specific to the role. Those are what will give the scores their meaning later on.

The candidate profile pulls together the identity (last name, first name, date of birth from which the age is calculated, contact details, status), the CVs uploaded as PDFs, and a profile summary. None of this is left to chance at interview time: before scoring anything, you have in front of you who you are meeting and for which role.

The Interview: Capturing What Matters, As You Hear It

The interview sheet is the heart of the tool. It places the hiring context (company, role, criteria, candidate identity) right next to the scoring grid, so you never have to switch screens in the middle of an answer.

Scoring rests on four base criteria, marked from 0 to 10: ease with the language, professionalism, technical skills, and foreign languages. Each score comes with a free-text field, because a number on its own does not say why you gave it. On top of that come custom evaluations in any number you like: a title, a mark out of 10, a note. That is where you put whatever is specific to a given role and does not fit the four standard boxes.

Two free-text fields round out the sheet: the candidate’s expectations and their distinctive traits. The point is not to reduce everything to numbers, but to keep a faithful record of the exchange while it is happening, ready to be reread once the dust has settled.

The AI Assists, It Does Not Decide

The application leans on a language model in several places, always in support and never in place of the recruiter.

It reads the CVs (PDFs included, through a model able to “see” the page) and proposes an identity: last name, first name, date of birth. The key word is “proposes”: these fields are submitted for validation, never written over an existing entry. It also drafts a profile summary from the CVs, which you can correct or regenerate. And at the end, it produces an interview summary that recalls the context, measures the candidate against the selection criteria, and offers a recommendation.

Two principles guide this assistance. First, everything stays editable: no generated text is locked in. Second, everything is transparent: a window lets you read the exact prompt sent to the model before triggering a new generation. You see what the machine has in front of it, and you keep control over what it does with it.

The interface comes in five languages: English, French, Estonian, German and Dutch. The AI follows that choice and writes its summaries in the display language. A recruiter running the interview in Estonian gets an Estonian summary; a colleague who switches the interface to French rereads it in French, from the same notes.

On the infrastructure side, the application talks to any OpenAI-compatible endpoint. You choose the URL, the key, and the model in the configuration, whether it is a hosted service or a model you run yourself.

Ranking and Weightings

This is where the tool earns its keep when the time comes to decide. A role’s dashboard ranks candidates by descending overall score, each with a score badge and small per-criterion bars to see at a glance where their strengths lie.

A position's dashboard: candidates ranked by descending overall score, each with a score badge and small per-criterion bars

The overall score is not a blind average. Each criterion gets a weighting from 0 to 3, specific to the role, adjustable with a slider. The score recalculates live as you move a slider, which lets you answer concrete questions: what if technical skills counted double? What if ease with the language mattered less for this particular role? Unscored criteria are simply ignored, without penalising the candidate.

Friday, end of the run of interviews. Three candidates sit within half a point of one another. You raise the weighting on technical skills, and the ranking reshuffles: the one who spoke best slips behind the one who coded best. The decision did not change its mood, it changed its criterion, and you can explain it.

The tool also lets you compare two candidates side by side: a radar chart overlays their profiles, a bar chart breaks down the gap criterion by criterion, and their interview summaries appear next to each other. The comparison stops being a feat of memory and becomes a piece of reading.

Two candidates compared side by side: a radar chart overlaying their profiles and a bar chart detailing the gap criterion by criterion

Light and Local, Where Conventional Tools Are Heavy

Most recruitment software comes as online platforms billed by the month, where your candidate data goes off to live on a third party’s servers. For a role you fill now and then, that is a lot of subscription, a lot of features you never touch, and CVs of real people handed to an outside service.

We took the opposite path. The tool fits in a single container that you launch on your own machine; the data stays local, in a file-based database that never leaves your computer. No subscription, no account to create, no CV slipping off to a platform. The only outbound calls are the ones you decide, toward the AI service of your choice, and even that one can be a model you host yourself. The same conviction guides our approach to automation: handle data as close to home as possible, and outsource only what truly must be.

Built to Adapt

Because we were hiring in Estonia, the tool knows how to handle the isikukood, the Estonian identity code, with its own validation. This is not a quirky detail: it is proof that the tool moulds itself to a context rather than imposing its own. Where a one-size-fits-all program forces you to squeeze your particulars into its boxes, a tool you control bends to yours. Your criteria, your weightings, your fields: all of it is shapeable because the code is yours.

Under the Hood

The application fits in a single container. The server is written in Python with FastAPI, the data lives in a SQLite database (in WAL mode to stay reliable with a single process), and the interface is a React application served by the same server. The whole thing launches with Docker and a volume for persistence.

These are the building blocks we use on our production projects, and they are precisely the kind of stack we wanted to introduce to a junior profile. The tool we built to hire him is, in a sense, already a sample of what he will be working on.

Why We Are Sharing It

It is a tool we first built for ourselves, and we open its code on GitHub: you can read it, run it locally for your own interviews, and adapt it to your process. It is a good illustration of how we work, the same way we apply to business process automation or to the intravitreal injection registry: a focused, sober tool that makes a decision clearer without taking it out of your hands.

If you want a tool of this kind shaped around your own process, book a conversation with transtorm.ai below.

Book a call

Frequently Asked Questions

Is the code available?

Yes. It is an internal tool we built for our own hiring, and its code is open on GitHub. You can read it, run it locally, and adapt it.

Does the AI decide who to hire for you?

No. The AI reads CVs, proposes identities for you to validate, and drafts summaries. Nothing is ever saved without review, and any generated text remains editable. The final ranking rests on your scores and your weightings, not on a machine’s opinion.

What languages does the tool work in?

The interface is available in five languages: English, French, Estonian, German and Dutch. AI-generated summaries follow the chosen display language, so each reviewer reads the assessment in their own language from the same notes.

Do you need a paid AI service to run it?

The application talks to any OpenAI-compatible endpoint: a hosted service like OpenRouter, or a model you host yourself. You choose the URL, the key, and the model in a configuration file.

How does the ranking work?

Each criterion is scored from 0 to 10. You assign a weighting from 0 to 3 per criterion and per role, and the overall score recalculates live. Unscored criteria penalise no one.