Charlie KrugThe Build Log

← All posts

Tighten a request or loosen a response. Either breaks a client.

Redline diffs two OpenAPI specs into a red/green tree marking every change breaking or safe, with a reason. The twist: tightening a request and loosening a response both break clients, in opposite directions.

You edited an OpenAPI spec, the git diff is four hundred lines, and exactly one of them breaks a client. The other three hundred and ninety-nine are keys that moved, a $ref that got renamed, an object that reindented when someone ran the formatter. A text diff paints all of it the same shade of red, so the one change that will page an integrator at 2am is buried in cosmetic noise, and eyeballing your way to it is a coin flip.

Redline is the pre-flight check for that exact moment: paste the old spec on the left, the new spec on the right, and get a tree where every path, operation, and field change is a node colored breaking or safe, each with one plain sentence saying why. Not a CI gate. Tools like oasdiff already do rigorous diffing for the pipeline; this is the ten-second gut-check before you open the PR, with no binary to install, no config file, and nothing leaving the tab.

It diffs meaning, not text

The first thing the engine does is stop looking at the file. It parses both documents and resolves every local $ref pointer before comparing anything, so the diff sees fully realized schemas, not the pointers that name them. That kills the dominant source of noise. If you split one inline schema into #/components/schemas/Pet and reference it, the text diff screams; Redline sees two structurally identical shapes and reports zero changes. Reordering keys, renaming a $ref target, factoring a shared object out: all of it produces nothing, because none of it changes what a client sends or receives. The $ref resolver handles nested and circular references without hanging, which matters more than it sounds, since a Node that contains a list of Node is a completely normal spec and a completely normal way to blow the stack if you resolve naively.

Breaking is directional, and the direction flips

Here's the part worth carrying away even if you never open the app. "Breaking" isn't a property of a change; it's a property of a change and which way the data flows. The rule Redline encodes is: a change is breaking if an existing client, written against the old spec, could send a request the new spec rejects, or could receive a response the new spec no longer guarantees.

Run that definition through the request and response sides and it comes out backwards from itself. On a request, getting stricter is what breaks you: add a new required query parameter, make an optional body field required, narrow a string to an enum of two values, and the old client, which happily omits or mis-fills the field, now gets a 400. On a response, getting looser is what breaks you: drop the guarantee that status is always present, remove a value the enum used to promise, and the old client that read that field falls over. Same textual edit, "this field is now required," is breaking on the way in and safe on the way out. Widening does the reverse: relaxing a request constraint or adding an optional response field is safe both times, because the old client still gets everything it expected and then some.

That asymmetry is exactly the thing a flat text diff cannot tell you and a human reading YAML at speed gets wrong. Each verdict traces to one named, tested function in the rule set rather than an inline heuristic, so when Redline says "breaking" you can go read the specific rule that decided it. The reason string is the actual product; a red node with no explanation isn't actionable.

What it doesn't do yet

It's honest about its edges. The rule set covers the surfaces that actually break clients, paths, operations, parameters, request bodies, and response schemas, and it grows one named rule at a time rather than pretending to be complete. It's client-side only by design, which is a feature: specs carry internal API shapes teams don't want uploaded anywhere, so parsing, resolution, and diffing all run in your tab, and the shareable link encodes the comparison itself, not a server-side session. Malformed JSON or a non-OpenAPI document gets a clear, pane-scoped error, not a blank screen.

Try it

Open Redline and hit Load example to drop in a Pet Store spec, v1 on the left and v2 on the right, then press ⌘/Ctrl+Enter. The tree fills the screen; flip on Breaking only to hide the safe changes, then paste your own before-and-after spec and read the blast radius before anyone else does. The whole engine is on GitHub.

Redline is live. Free, in your browser, no signup.

This post is part of the build log: every app my automated factory ships gets written up here, honestly. Browse everything at apps.charliekrug.com. Comments are open below.

Comments

Loading comments…