Skip to Content
DecisionsAll decisions

Decisions

25 decision records, newest first. Each one is the context, the options, the choice and the consequences — written when the decision was made, not reconstructed afterwards.

An accepted record is never edited to reverse it. A decision that changes gets a new record that supersedes the old one, and the old one stays exactly as written, because the reasoning that turned out to be wrong is the part worth keeping. ADR 0021 reversing a scope exclusion from ADR 0003 is the worked example.

If you are reading one of these first, read ADR 0012. karani drafts everything and submits nothing, and almost every other decision here is downstream of that one.

ADRDecisionStatus
0025Every pass has a deadline
Why every pass has a deadline, after a hang silenced the pipeline for 40 hours.
accepted
0024Interview prep fires on the state change
Why interview prep fires on a state change rather than on a verb.
accepted
0023A static submission console, and a write-back that creates labels
A static submission console, and the write-back that gives the funnel its labels.
accepted
0022A conversion ledger, and promotion that refuses on noise
A conversion ledger, and a promotion rule that refuses to crown a winner on noise.
accepted
0021Computational biology is in scope; exclusions become liftable
Why computational biology is in scope, and how a built-in exclusion becomes liftable.
accepted
0020Submission-ready documents: ATS-plain .docx, PDF for humans
Why the pack renders to an ATS-plain .docx and a PDF, after 121 packs produced 0 applications.
accepted
0019Hosted Claude tiers behind a monthly allocation
Why billed work degrades to a local model instead of halting or overspending.
accepted
0018Liveness must live outside the process it watches
Why the thing that watches the pipeline cannot run inside it.
accepted
0017Pluggable LLM providers, local-first qualification
Providers as a registry, and why bulk qualification runs on a local model.
accepted
0016Production hardening: dedup, locks, ledger, verify gate
The hardening pass: cross-run dedup, advisory locks, a run ledger, a verify gate.
accepted
0015One namespace, one config file, one CLI — pip-installable
One namespace, one config file, one CLI — and why it is on PyPI.
accepted
0014Per-job artifacts in object storage + a measured humanizer pass
Why each job’s documents live in object storage, and why the humanizer is measured.
accepted
0013LangGraph for background orchestration — and nowhere else
Where LangGraph is used, and the larger set of places it is not.
accepted
0012Autopilot drafts, human sends
Why karani drafts everything and submits nothing. The load-bearing decision.
accepted
0011Notion board as a karani-owned mirror, not a second store
Why the Notion board is a one-way mirror that karani owns the schema of.
accepted
0010Slack as the two-way daily surface (Socket Mode bridge)
Why Slack is the two-way surface, and what it is allowed to do.
accepted
0009Ledger-first memory with mem0 as a derived index
Why the memory ledger is the system of record and the vector index is disposable.
accepted
0008MCP server as the interactive interface layer
Why the MCP server is a thin adapter with no logic of its own.
accepted
0007Agent mode is opt-in, not default
Why the tool-using agent is opt-in and never the daily batch.
accepted
0006In-memory storage fallback as a real code path
Why running with no database is a real code path rather than a test shim.
accepted
0005Application state machine as columns, not a separate table
Why the application state machine is columns on a row and not its own table.
accepted
0004Normalized content hash + canonical hash for dedup
How a posting is recognised as one already seen, across sources.
accepted
0003OpenRouter default, Anthropic optional
Which LLM provider is the default, and which is optional.
accepted (supersedes 0.1’s Anthropic default)
0002Positioning: SF-band global remote, not Kenya-specific
The positioning the whole pipeline exists to serve, and why it is location-agnostic.
accepted (supersedes an implicit v0.1 positioning)
0001Tiered filter (deterministic → LLM → agent) instead of one LLM pass
Why there are two filter tiers and not one model call per posting.
accepted
Last updated on