For founders hiring engineers · web app + CLI

The ATS your agents can run.

Post a job, share a link, and let a model read every résumé with the quote behind each verdict. Then move the pipeline from the web app — or from krinoa … --json. A person always decides.

  • Free while in beta
  • No card
  • No sales call
krinoa — zsh
$ krinoa apps list --job ENG7K2 --stage screening \ --sort score --dir desc --fields id,candidate.name,score --json{ "items": [ { "id": "A-142", "candidate": { "name": "Kayla Morgan" }, "score": 84 }, { "id": "A-139", "candidate": { "name": "Tomás Reyes" }, "score": 71 }, { "id": "A-127", "candidate": { "name": "Priya Nair" }, "score": 58 } ], "nextCursor": null } $ krinoa apps show A-142Kayla Morgan <kayla.morgan@example.com>A-142 · Backend Engineer (ENG7K2) · screening 84 · well evidencedSix years of backend work, Postgres at real scale; lead scope unclear. coverage · 3 of 4 evidenced 5+ years backend "Vanguard, 2018–present" r·p1 Postgres at scale "…40k writes/s on Postgres…" a·q1 ~ Led a team "coordinated 3 engineers" r·p1 ? Kubernetes nothing found  findings Scope at Vanguard is unclear r·p1 → probe r3: Ask what they owned end-to-end at Vanguard rubric v3 · gpt-5.6-luna · Reviewed with AI assistance. A person makes every decision. $ krinoa apps move A-142 interviewA-142 → interview

Shipping log

Beta · shipping weekly
  • Verified email on both doors — sign-up and invitations
  • Candidate erasure, export and retention sweeps; WhatsApp threads
  • The read: quoted evidence, coverage per requirement, ask/probe, re-read deltas
  • Interview scheduling with real calendar invites and RSVP
  • Candidate email: queued sends with recall, inbound routing, quarantine
The problem

Hiring tools were built for HR departments. You're three engineers and a spreadsheet.

The incumbents start at a sales call and end at a seat licence. The free tiers give you a board and a black-box score. Neither one has a command line, and neither one shows you why a candidate ranked where they did.

A demo before a price.

Most ATS pricing pages end in "Get in touch".

Scores without receipts.

A number, no quote, no line it came from.

Nothing your agent can drive.

Web UI only, or an undocumented API.

How it works

Post. Read. Decide.

01

Post a job.

Title, form, done. You get a careers page, a JSON feed and an embed snippet for your own site.

careers/acme/ENG7K2
02

The read happens on arrival.

Every résumé, cover letter and answer is read against the job's requirements. Each verdict carries the quote and where it was found.

✓ Postgres at scale "…40k writes/s…" a·q1
03

You decide, from anywhere.

Move, ask, probe, book, reject. From the board, or from the command line.

krinoa apps move A-142 interview
The read

Every verdict comes with the quote it came from.

Not a score you have to trust. Coverage, requirement by requirement: the sentence that supports it, and the page or answer it was found in.

  • Coverage, not a grade. Met, partial, unclear or not met — per requirement, with the quote beside it.

  • Quotes are checked. A quote that can't be located in the résumé or answers is dropped, and the requirement drops to unclear.

  • Ask or probe in one click. A gap becomes a question to the candidate or a prompt for the interviewer in that round.

  • New evidence, new read. When an answer or résumé changes, the read runs again and reports what moved.

  • It can rank. It cannot reject. A person moves every candidate; the read only ranks and quotes.

The candidate packet in Krinoa, open on the read tab: coverage for every requirement, with the quote beside it.
The packet · facts above, the read below · a person makes every decision
Agent-native

Your agent already knows how to use it.

Every command is non-interactive, JSON-first and describes its own output. Claude Code, Codex, Cursor, a cron job — anything that can run a shell can run your hiring pipeline.

  • The JSON is the API's response, unchanged. Lists page with nextCursor; --all follows the cursors for you.

  • Keep the context window small. --fields id,candidate.name,score trims the payload; unknown fields are an error that names the valid ones.

  • No interactive prompts. A destructive command without --yes exits 2 with the changes and the exact line to re-run.

  • Self-describing. Every --help ends with the response shape, and krinoa schema prints the OpenAPI document.

  • One key, one variable. KRINOA_API_KEY from Settings › CLI access. No browser, no config file.

Get in
npx krinoa login                     # or: export KRINOA_API_KEY=krinoa_…krinoa jobs list --jsonkrinoa apps list --job ENG7K2 --stage screening \  --sort score --dir desc --fields id,candidate.name,score --json
The read, in your terminal
krinoa apps show A-142             # the packet, read includedkrinoa apps reads A-142            # every read, newest firstkrinoa apps probe A-142 --round technical "Ask what they owned"krinoa apps reread A-142           # read it again
Destructive commands refuse, and hand back the line
$ krinoa apps reject A-127 --reason "no backend experience" --jsonerror: CONFIRMATION_REQUIRED: this will move A-127 to rejected and email the candidate{  "code": "CONFIRMATION_REQUIRED",  "changes": [    "A-127 screening → rejected",    "queues an email: \"Update on your application to Backend Engineer\""  ],  "confirmCommand": "krinoa apps reject A-127 --reason 'no backend experience' --json --yes"}$ echo $?2

Also: /llms.txt, a public JSON feed per careers page, and OpenAPI at /api/v1/openapi.json.

With your agent

Point Claude Code at it. Or any agent with a shell.

It reads --help, runs the commands, and stops where a person is required.

  • Works with
  • Claude Code
  • Codex
  • Cursor
  • Gemini CLI
  • cron
  • CI
claude — ~/hiring

Screen the new applicants on ENG7K2: move strong ones to interview, probe anything unclear, reject anyone with no backend experience.

  1. Bash(krinoa apps list --job ENG7K2 --stage screening --sort score --dir desc --fields id,candidate.name,score --json)

    3 items · A-142 Kayla Morgan 84 · A-139 Tomás Reyes 71 · A-127 Priya Nair 58

  2. Bash(krinoa apps show A-142 --json --fields screeningDetail.read.coverage)

    3 of 4 evidenced · "Led a team" partial (r·p1)

  3. Bash(krinoa apps probe A-142 --round technical "What did you own end-to-end at Vanguard?")

    queued for round r3

  4. Bash(krinoa apps move A-142 interview)

    A-142 → interview

  5. Bash(krinoa apps reject A-127 --reason "no backend experience" --json)

    exit 2 · CONFIRMATION_REQUIRED · would email “Update on your application to Backend Engineer”

Kayla Morgan is in interview with a probe queued for the technical round. Tomás Reyes needs a closer look: his Postgres requirement is unclear, not missing.

Rejecting Priya Nair would email her, so I stopped. Run this if you agree:

krinoa apps reject A-127 --reason 'no backend experience' --json --yes

Give it the tool.

Two lines in your agent's instructions. Every command describes its own output.

Nothing hangs.

Nothing prompts. A destructive command without --yes exits 2 with the changes and the confirm command, which the agent hands to you.

Cron and CI, too.

A cron job or CI step works the same way. Same key.

CLAUDE.md
# Hiring- `krinoa` is on PATH and `KRINOA_API_KEY` is set. Run `krinoa --help` first.- Never pass `--yes`. Show me `changes` and `confirmCommand` instead.
Your model

Bring your own model. Or don't.

Any OpenAI-compatible endpoint.

LiteLLM, OpenRouter, Groq, Azure, a local Ollama. One base URL, one key (optional for local).

On the record.

Every read stores the model id and rubric version it ran under. A daily budget stops the spend where you set it.

Or no model at all.

Unset the key and everything works except the read. The AI notice to candidates disappears with it.

The rest of the job

Everything around the read.

Candidates get a page, a reply, an invite.

The Krinoa pipeline board with candidates spread across applied, screening, interview and offer columns.
The pipeline board · every stage, every candidate, one screen

Careers page, feed, embed.

Hosted page with your logo; JSON feed; embed.js drops the openings — and the apply form — into your own site.

Email that leaves a trace.

Every message is recorded, and a queued one can be pulled back. Replies land in the thread; strangers land in quarantine.

Interviews with real invites.

Propose times or book one; the candidate gets a calendar invite, and accept or decline comes back into the thread.

WhatsApp threads

On your own Meta number, with confirm and reschedule buttons.

Discussion, @mentions, inbox.

Comments on the packet, one bell, one inbox — for you and the interviewer you invited for one round.

Export or erase a candidate.

One command removes a candidate and leaves an audit entry with no personal data.

Compared

What you don't get anywhere else at this size.

How most hiring tools behave, next to how Krinoa behaves.
What it doesMost hiring toolsKrinoa
PriceAsk salesOn this page
First stepBook a demoSign up
Screening outputA scoreA score, the quote, and where it was found
RejectionAI can auto-rejectA person moves every candidate
Command lineEvery command, JSON-first, self-describing
ModelTheirsAny OpenAI-compatible endpoint, or none
Candidate repliesBest effortEvery application gets an answer; the engine sends it

Seen a tool that does one of these? Tell us.

Trust

It ranks and quotes. You decide.

Advisory only.

A person moves every candidate; the read only ranks and quotes.

Candidates are told.

The apply form carries an AI-use notice whenever a model is configured, and drops it when none is.

Your data stays yours.

Export a candidate, erase a candidate, keep the audit trail. Retention sweeps run on your schedule.

Doors are guarded.

Verified email on sign-up and invitations, rate limits on every public form, a captcha and honeypot on apply.

Pricing

Free while in beta.

No card. No sales call. No "contact us".

Beta

Everything on this page.

$0

  • Unlimited jobs and candidates during beta
  • The read on every application (bring your key)
  • CLI + API access
  • Careers page, feed and embed
  • Email, scheduling, WhatsApp
  • Team seats and interviewer invites
Start free

Pricing will be published on this page before launch.

A note from the founder

I built Krinoa because every hiring tool I tried wanted a call before a price and gave me a score without a reason. This one runs from a terminal, shows its receipts, and never makes the decision for you.

It is a beta. The web app, the read, the CLI, careers pages, email, scheduling and WhatsApp are in and tested. Billing is not — it's free until it is. Reporting is thin. If you hire engineers and you'd rather script the boring parts, I'd like you in early.

FAQ

The questions that decide it.

Does the AI reject candidates?

No. A person moves every candidate; the read only ranks and quotes.

Which models can I use?

Any OpenAI-compatible endpoint — LiteLLM, OpenRouter, Groq, Azure, a local Ollama — or the Vercel AI Gateway. The model id is recorded on every read.

What if I don't set a key?

Everything except the read. Board, threads, invites, careers page, CLI. The AI notice to candidates disappears too.

Do I need the CLI?

No. The web app is complete. The CLI exists so an agent — or a script — can do what you'd otherwise click.

Do candidates know a model read their application?

Yes, when one is configured: the apply form says so, and every read ends with the same line.

What happens to candidate data?

You can export or erase any candidate on request; erasure leaves an audit entry without the personal data. Retention sweeps are yours to schedule.

Post a job. Read the queue. Hire someone.

Start free

Free while in beta · No card · No sales call