How building, zoning, and safety codes became a library any AI assistant can read. Open, free, and built to cite the real section.

This started with a simple want... to get better at the way I search building and zoning codes. They're boring to read, and honestly difficult to traverse. Finding the right section at the right moment, without needing a second opinion, is harder than it should be. They span page after page, and most of the time the thing I'm actually after is just... hiding in plain sight: the bottom row of a table, a footnote, the fine print. So I set out to fix that. That's what led me into this rollercoaster of a ride... where what I thought I'd accomplished on day one turned out to be nowhere close.
So far, I'd been getting by: Upcodes, a Google search, punching in section numbers when I had them. Then AI search started popping up everywhere, and eventually I was just asking ChatGPT, or Claude on the desktop. And the momentum was upward, genuinely... most of the time it got me most of what I needed. But it lacked the one thing that matters: reliability. The web search inside Claude and GPT is more limited than you'd expect, and the moment I went looking for something tricky, something properly buried, the token consumption would max out before it ever got to the answer.
Right around then, agent tools like OpenClaw1 and Hermes2 were trending hard, and I figured... why not put that to use. The idea was simple enough: a Telegram chatbot wired into Claude Code on my desktop, so the codes would be there whenever I wanted them, wherever I happened to be. But an agent is only ever as good as what it can actually reach. For any of this to work, it still needed something underneath it. A working library. A real database of the codes themselves that it could pull from, cleanly.
A while back I'd borrowed a simple idea, using plain markdown files as the database for an agent, no vectors, no embeddings, none of the heavy machinery3, and built a small support agent on top of it for another product of mine: Ori, the in-app assistant on timeit360.com. It worked... honestly better than it had any right to, but mostly because the data was small. So the plan here was just to borrow that: take the publicly available building code PDFs, turn them into clean text and images, and let the agent read off that. Simple enough on paper. The catch was making the conversion steady, reliable page after page, code after code. That, it turned out, was the real work.
The trouble is that building codes are gloriously inconsistent. A conversion that handles one chapter cleanly will trip over the next: a table that won't sit still, a footnote that wanders off, an older code like the '68, dense and archaic, its words run together in the old justified type. Hand-tuning a recipe for each one is a road with no end... you fix one thing and quietly break two.
So instead of hand-tuning a recipe, the trick was to let the process find one itself: run a pass, score how faithful it came out, adjust, run it again, round after round, until something held up across the whole messy pile and not just one tidy chapter. That loop isn't mine. It's the auto-research methodology Andrej Karpathy put out into the world4: write the goal in plain language, let it try, grade itself, repeat. He aimed it at training models; the same shape works just as well on untangling legal PDFs. Which is the counterintuitive part: the breakthrough wasn't some clever method I'd dreamed up... it was automating the search for one.
And then it clicked. With the library finally clean enough to trust, the rest came together fast. I could ask a question the way I'd actually ask it, in plain English, half-formed, the way it comes out when you're mid-drawing, and the agent would go find the right section and hand it back... not a summary, not its best guess, but the actual code text, word for word, with the section number sitting right next to it.

Because it was wired into Telegram, all of that was happening on my phone. On site. On the train. In a meeting I probably should've been paying more attention to. The thing I'd wanted back at the very start (the right section, at the right moment, without needing a second opinion) was suddenly just... there. In my pocket. For about a week, it really did feel like I'd quietly solved the whole thing.
Every few days, it would just... stop. The bot lived on a machine under my desk: Claude Code running on the desktop, the whole thing tethered to one computer that had to be awake and online for any of it to work. Telegram bots, it turns out, do not love running unattended. No error, no drama, just silence. I'd usually find out at the worst possible moment, on site, reaching for a section mid-conversation, getting nothing back. Reboot it, and it'd be fine again... for a few days.

It took a few of those reboots to see the real problem. It wasn't the bot. It was the machine under the desk. Anything you have to nurse back to life twice a week isn't infrastructure. It's a pet. You can't build a habit, let alone real work, on something that's only there when the right computer happens to be switched on. The fix wasn't a more reliable bot. It was getting rid of the desk entirely.
So the codes came off the desk. They went into a database that lives in the cloud, with a small service in front of it that's simply... always on: nothing to keep awake, nothing to reboot at midnight. You reach for it, it answers. That one change quietly fixed the thing that had been killing the whole project.
The timing was lucky. Right around then, MCP (the standard that lets you plug an outside source of knowledge straight into Claude, ChatGPT, or your editor) was taking off, and connectors were suddenly everywhere. Which reframed the whole thing: don't build an app nobody downloads, and don't chain a bot to one machine. Build the connector, and let the codes show up inside whatever AI you're already talking to. Paste a URL, and there they are.
That's roughly the shape of what's live today. Getting there, though, was the rollercoaster.
And it was a rollercoaster: the good kind and the exhausting kind, often in the same week. One code book became several: the building code pulled in zoning, then mechanical, plumbing, fuel gas, energy, the fire code, the housing guidelines, the federal accessibility standards. Then older editions: 2014, even the 1968 code, in its own archaic numbering, because "which year applies?" has a real answer the tool ought to know. The login got built, fought with, and thrown out: it's public law, there's nothing to protect, so the whole thing went open: no account, paste a URL, done.
Plenty broke in unglamorous ways. Tables came out of the conversion mangled: rows crushed into a single cell, which is exactly the part an architect needs. Fixing them meant pointing a small army of cheap agents at the pile, one table at a time. Some experiments got expensive enough to teach me a rule I keep now: measure before you trust it. One feature got built, tested, and then deliberately shipped switched off, because the numbers said it made the answers worse. Half of this was deciding what not to keep.
Testing it was its own little education. First came the general questions: does this even work? Then the deliberately dumb ones, the most naive phrasings I could come up with, "do I need a permit to knock down a wall?", on the logic that if it survives a layperson at their vaguest, it survives anything. Then it circled back to how the questions actually get asked on a working day: by section, by topic, the way an architect already half-knows what they're after. Which, as it turns out, is exactly what it's best at.
Somewhere in the middle of all this, without my quite noticing, it had stopped being a tool for looking up the NYC building code.
It had become a library. Not "the NYC building code" anymore but a shelf of them: the building code across three editions, zoning, the mechanical and plumbing and energy codes, the fire code, the federal accessibility standards. Tens of thousands of sections of building law, open and free, that any AI you already use can read just by connecting to it. It's built so the next city slots in the same way.
When it can't find something, it says so, rather than inventing a plausible number to fill the silence. When the first answer is close but not quite, you can push it, the way you'd narrow any search, until it lands. It won't always get there on the first try. It will never make something up. For legal text, that's the trade you actually want.
Which is more or less where this started: mid-drawing, one number between you and the next move. Except now the answer comes back in the code's own words, with the real section, on whatever you've already got open, from something you never have to reboot.
It's free, it's open, and it's live at buildingcodes.live, still growing. So: which codes should we add next?
(Skip this if you just want to use it.)
Getting the right section out of tens of thousands took a few rounds of its own. The short version of how the search evolved:
For the genuinely curious: it's a Next.js app on Vercel, with one MCP connector per jurisdiction. The corpus lives in a Neon Postgres database, with pgvector holding the embeddings (OpenAI's text-embedding-3-small). Every query runs the lexical lane (Postgres full-text) and the semantic lane (pgvector nearest-neighbor) at once and fuses them with Reciprocal Rank Fusion. If the semantic side is ever down, it quietly falls back to lexical-only rather than failing outright.