v0.4 · self-hosted · MIT · Python 3.11+
Job hunting is a data pipeline problem.
Nine job boards, thousands of postings a day, and maybe five of them are a role you would take at a company that would pay you properly. Finding those five takes forty-five minutes a day and still misses most of them.
karani is a clerk for that problem. It reads every posting, drops the ones that fail your rules before any model is called, scores what survives against your actual resume, drafts the whole application — and hands you the pen. You press submit. It never does.
What it does with a posting
Two tiers, and only one of them costs money
The first tier is arithmetic. Role family, seniority, geography, remote status, comp anchored to a currency keyword, skill overlap against your profile — all word-boundary matched, all deterministic, no model involved. About 95% of a pass ends here, for free.
workable--That split is the whole architecture (ADR 0001). Running a model over every RemoteOK posting would be expensive and no better; running one over the two dozen that survived is cheap enough to be worth doing carefully.
What a model is for
A verdict you can argue with
The second tier reads the survivors against your resume and comes back with a score, a three-way verdict, and claims about you that each carry the line of your own resume behind them.
Strengths
- Has owned an event platform at this scale before
- Owned the event platform at a 40-engineer company: Kafka to ClickHouse, 11 downstream teams, 2.4bn events a day, p99 ingest lag under 90 seconds.
- The posting's deadline-scheduling problem is one she has shipped a solver for
- Rebuilt the dispatch planner for a Nairobi logistics operator: replaced a nightly batch with an incremental solver, cutting median delivery time from 2h10m to 45m across 1,400 daily drops.
Gaps
- lowKubernetes operator experience
- She has run workloads on Kubernetes but has not written an operator. Name the control-loop work in the dispatch planner, which is the same shape.
Recommended positioning
Lead with the dispatch planner, not the event platform. The posting is about reconciling state across regions on a deadline, and that is the harder of her two stories.
Hires globally at one band, states it in the posting, and the fleet-scheduling work is a direct match for the dispatch rebuild. Apply today: posted two days ago.
Every strength has a quote. That is not a prompt asking nicely: a claim whose citation karani cannot verify in your own records is dropped, not repaired (CLAUDE.md 4.13 ), because a fabricated story gets probed for ten minutes by someone who interviews for a living.
The disagreements are the useful part. When karani says skip and you would
apply, tell it — karani verdict 1544 apply — and that pair becomes a
few-shot example in the next qualify prompt. Its taste converges on yours
with no retraining.
The last mile
It fills the form in. You send it.
karani console writes one self-contained HTML file: every pack waiting to
be sent, each with the apply link, the rendered documents, and a
field-by-field answer sheet with a copy button on every field. No server,
no port, no process — it opens from iCloud on a phone, which is where a
queue actually gets cleared.
The sheet answers that job’s real questions. Greenhouse, Lever and Ashby publish their application forms on the same public endpoints karani ingests from, so the wording and the option values are the company’s own rather than a guess at a standard form.
And every answer says where it came from. Work authorization, sponsorship, relocation and start date are resolved from legal facts you declare and sign, by code, never by a model — the same question has opposite correct answers depending on the role’s shape, so “the model usually gets it right” is not a defence (ADR 0023). Demographic questions are left blank. Anything karani has no source for is flagged rather than invented.
Ways in
One pipeline, five front doors
All five are thin adapters over the same storage and the same runners, so they cannot disagree about what a verb does.
karani runThe command line37 verbs, one entry point. Every one returns an exit code, so each composes into a shell chain.
karani mcpAn MCP client27 tools over stdio. Ask your assistant what to do on the job hunt today and it assembles the answer itself.
karani slackSlackReview cards with buttons, and the same verbs back as text. Approve a pack from your phone.
karani consoleThe consoleOne HTML file with the whole queue in it. The only surface with no network at all.
karani watchYour inboxReads the replies over a read-only scope and moves the state machine. It cannot send, delete or mark read.
What it costs
Billed work degrades. It never halts, and never overspends.
The reference configuration runs bulk qualification on a local model at zero token cost, and keeps a hosted model for drafting — the low-volume step where quality is what gets the interview.
Past the cap, or with no API key set, a billed provider is swapped for the local model and the pass says once that it happened. A missing key is never a hard failure and a spent budget never stops the hunt (ADR 0019).
What leaves your machine
As little as you configure
karani is self-hosted and every integration is opt-in. Your resume, the database and every generated pack stay on disk.
| Destination | What goes there |
|---|---|
| Job boards | Nothing about you. Public endpoints, read only. |
| LLM provider | The posting, your resume, your positioning, past verdicts as examples. Set provider = "local" and nothing leaves. |
| Slack, Notion, object storage | Shortlists, packs and application state — only if you configure them. |
| Gmail | Nothing outbound. The watcher holds a read-only scope and cannot send, delete or mark read. |
API keys live in .env and never in karani.toml, which the docs build
checks: a config field whose name looks like a credential fails it.
Where to start
Four ways in
| If you want to | Go to |
|---|---|
| Have it running in ten minutes | Installation |
| Hunt for something other than the defaults | Saying what to hunt |
| Know what a flag does | Command line |
| Drive it from an assistant | Connecting an MCP client |
| Understand why it works this way | Decisions |
| Run it unattended | Scheduling |
Where it stands
One user, and it is his own job hunt
karani is on PyPI as karani. It is a
personal tool rather than a product: it is built for one person’s hunt, it
makes no multi-tenant assumptions, and there is no hosted version and no
plan for one. If you want to use it, fork it and rewrite karani.toml and
data/resume.md — the vision page says what that
involves and what karani deliberately will not do.
The one thing it will never do is press submit for you.