Engineering4 min read

Negative Programming: the habit our coding agents quietly gave us

We didn't set out to build a codebase defined by what it must never do. Our agents got us there one correction at a time. Here is how we dug out.

Ash Barot

Ash Barot

Founder & CEO

A few months into building with coding agents, one of our engineers opened a file at the center of the system and stopped. It had grown into a wall of prohibitions. Line after line of "reject this," "block that," "this must never happen." Nobody had decided to write it that way. It just accumulated. We started calling it negative programming, and once we had a name for it, we saw it everywhere.

Negative programming is when you define a system by what it is not allowed to do. if not this and not that and not the other, then proceed. The body of the logic is a list of everything you are trying to prevent, and the real intent, the thing the code is actually for, ends up buried somewhere underneath.

We did not get here through laziness. We got here through the workflow itself. Building with agents is a conversation, and the conversation is mostly corrections. Something breaks in review, so you tell the agent "don't let empty records save." It obliges. Something else breaks, so you say "don't allow a shift with no worker." It obliges again. Agents are obedient. You hand them a complaint, they hand back a guard against that exact complaint. Ship fast enough and the guards pile up quicker than anyone is reading them.

Here is what took us a while to see. The set of wrong things is infinite. The set of right things is small. Coding by exclusion means trying to enumerate the infinite set, one incident at a time, forever. There is always one more bad input nobody thought to ban.

We were not building a system. We were playing cat and mouse against our own code, and the mouse was infinite.

The irony was not lost on us. We build credentialing software. Credentialing is about the purest allowlist there is. A provider is not cleared because they dodged every possible disqualifier. They are cleared because they meet a defined set of positive requirements: a verified license, confirmed education, an active DEA registration, a clean primary-source check. Meet the list and you are in. Miss any of it and you are not. We were shipping exactly that logic in our product while quietly doing the opposite of it in our code.

What we changed

So we flipped the default. Instead of listing what a piece of the system must never do, we define what it should do, precisely, and let everything else fail on its own. A shift assignment is valid when there is a worker, a client, a time that does not overlap, and credentials that are current. Four positive conditions. Everything outside them is invalid without anyone having to predict it in advance.

We leaned hard on encapsulation to make that stick. Each domain gets a tight contract. Here is what I accept, here is what I return, here is what I promise. A domain does not defend against the whole world. It says yes to its own small set and nothing else. When we build with agents now, we hand them that contract as the frame, so there are fewer open corners where a new special case can slip in.

The code got smaller. A method that states what it does is shorter than one that lists everything it forbids. Small methods are easy to test, because there is a finite set of inputs that count as valid. They are easy to change, because the contract is right there. And a person can still hold them in their head, which brings me to the part I am genuinely unsure about.

The part I am unsure about

We spend real money keeping this code readable by humans. We run briefings where an engineer walks the team through how a piece works and how it is wired together. It is not cheap. My instinct says it is worth it, because the contract, the thing a human carries in their head, is what keeps the system honest when the agents are moving fast.

But I hold that loosely. Almost no engineer today reads assembly or pokes at a binary. That layer moved out of human hands and nobody grieves it. Maybe reading code line by line goes the same way, and in a few years the briefings look quaint.

Even if that happens, I think positive programming still wins. A system defined by what it does can be reasoned about, by a person or by the next agent. A system defined by what it forbids is a pile of exceptions that nobody, human or model, can summarize. The reader might change. The need for a contract small enough to understand does not.

We are writing this down because we suspect we are not special. If you are building with coding agents, the same drift is probably happening in your codebase right now, one reasonable "don't do that" at a time. Negative programming is not a flaw in the agents. It is the natural shape of a workflow built on corrections. Naming it was the first thing that helped us.

Filed undernegative programmingpositive programmingcoding agentsAI agentsdomain-driven designcode qualityencapsulationprimary-source verificationcredentialing
Ash Barot

Ash Barot

Founder & CEO

Subscribe

Get each new piece by email.

New writing on building autonomous credentialing, sent as it goes up. No spam — unsubscribe any time.

See it work a real file.

Thirty minutes, one placement, worked live — start to submit-ready.

Negative Programming: the habit our coding agents quietly gave us — Credentialing Agents