Sulabh Sethi · Blog ← Main Site

Build Log: Nyaya Mitra, Plain-Language Search for India's New Criminal Laws

A case study of something I actually shipped: a tool that lets an officer ask a question in plain words and get the right section of the new BNS, BNSS, and BSA, explained simply. Here is how it works and why I kept it boring.

17 June 2026 · 5 min read

Most of my posts so far have explained ideas. This one is a build log, a look at something I actually shipped, because explaining concepts is easy and shipping is where the real lessons hide.

The tool is called Nyaya Mitra. It does one thing well: you ask a question in plain words, like “what is the punishment for snatching a phone,” and it finds the right section of India’s new criminal laws, explains it in simple language, and shows you which section it came from. It runs behind the police dashboard on this domain.

Here is the problem it solves, the decisions I made, and why the boring choices were the right ones.

The problem

In 2024 India replaced three colonial-era laws at once. The Indian Penal Code, the Criminal Procedure Code, and the Evidence Act gave way to the BNS, the BNSS, and the BSA. Overnight, every section number that officers had known for their entire careers changed.

So you have a very real, very practical problem. An officer needs to find the correct new section for a situation, understand what it actually says, and often map it back to the old law they still think in. The official text is long, dense, and freshly renumbered. Flipping through a PDF under pressure is nobody’s idea of a good time.

That is the gap Nyaya Mitra fills. Ask in normal language, get the right section, plain explanation, old-law mapping. Nothing more.

Decision 1: do not let the model answer from memory

I wrote a whole post on why a raw language model is dangerous for legal questions. It will happily invent a section number that sounds real and does not exist. For law, that is not a quirk, it is a disqualifier.

So Nyaya Mitra is built the way I argued for in that post. It never asks the model to recall the law. It retrieves the real text first, then asks the model only to explain what was retrieved. The model is a clerk that reads the page, not an oracle that remembers it.

Here is where people expect me to say I reached for a fancy vector database. I did not.

I loaded the actual text of the BNS, BNSS, and BSA into a plain PostgreSQL database, one row per section, and used Postgres’s built-in full-text search to find matches. A query like “punishment for theft” gets turned into a search, ranked by relevance, and the top real sections come back. That is it.

Why so plain? Three reasons, all of which I have written about before.

It is transparent. I can see exactly why a section matched, which matters when the output touches real police work.

It runs on almost nothing. Postgres full-text search uses no GPU and is fast on a modest box, which is the only kind of box I run. No special infrastructure, no extra service to keep alive.

And it was enough. For a defined body of text like the law, good old full-text search handles the large majority of real queries well. Reaching for something heavier would have been engineering for a problem I did not have.

Decision 3: the model only explains, and always cites

Once the right section is retrieved, a language model takes over for the part it is genuinely good at: turning dense legal language into a plain explanation, and noting how it maps to the old law. Crucially, the section number sits right there next to the explanation, so the officer can verify the source rather than trust the machine.

If the search finds nothing relevant, the honest answer is “I could not find a matching section,” not a confident invention. A tool that admits it does not know is worth far more than one that never stops talking.

What it runs on

The whole thing is deliberately small. A PostgreSQL database holding the law, a lightweight service that handles the search and the model call, and the police dashboard’s existing login in front of it. It sits on the same modest server as everything else I run. No GPU, no cluster, no drama.

That is a theme across my work, and it is intentional. The unglamorous stack is easier to run, cheaper to keep alive, and far easier to reason about when something goes wrong at an inconvenient hour.

The honest limits

A build log is not an advertisement, so here is where it falls short.

It is only as good as the text loaded into it. If the law is updated, the database has to be updated too. Garbage in, garbage out never retires.

Plain full-text search can miss a section when the words in the question do not overlap with the words in the law, even if the meaning is the same. This is the one place where adding semantic search later would genuinely help, and it is on my list.

And the model’s plain-language explanation, however clear, is still a convenience, not legal advice. For anything operational, the officer reads the actual cited section. The tool points to the page. The human makes the call.

What I would tell anyone building something similar

Start with the boring version. I could have spent weeks on a heavy retrieval pipeline before anyone had searched for a single section. Instead, Postgres full-text search plus one careful model call gave officers something genuinely useful, on hardware I already had, that I can explain end to end.

The boring version shipped. The clever version would still be in a planning document. That trade, again and again, is most of the job.

If you are working on legal or government tooling and want to compare notes, I am easy to reach. Details are on the home page.