← Blog

On August 20 we renamed one method. Every tool already saved on a device broke.

On August 20 we renamed one method. Every tool already saved on a device broke.

The method was fokl/ai.generate. We renamed it to fokl/ai.ask because the old name no longer matched what it actually did. A one-line change — the kind you make without thinking twice on a normal web app, because the browser just fetches the new code the next time someone refreshes.

A FOKL tool doesn't refresh. It's a single HTML file somebody generated and kept, running on its own in a sandboxed iframe with no network access of its own. Its only way to talk to anything outside itself is a bridge: a small, versioned API the tool calls by name. When we deleted the old name and shipped the new one, we didn't break our own code. We broke every tool that used the AI feature and had already been saved — files sitting on people's devices, written days earlier against a method that no longer existed on the other end of the bridge. There was no next deploy to fix it for them. There was no update to push. The tool just kept calling a name nobody answered, until somebody rebuilt it from scratch.

That's the part that doesn't show up if you've only ever shipped server-rendered software: an ordinary API can take a breaking change, because the client and the server ship together, on your schedule. Software that's supposed to be yours — something you export, keep, and run on a device that may never see another update — doesn't get that deal. The bridge has to be the one thing that never breaks, because it's the only thing standing between a file from six weeks ago and a host that's shipped forty times since.

So the fix wasn't "stop renaming things." It was a rule: a method name, once published, can be superseded, but never withdrawn. fokl/ai.ask is the current name now; fokl/ai.generate still resolves, quietly, through a table of old names checked before anything else runs — so the six-week-old tool keeps working exactly as it did the day it was saved, and the newest tool gets the clean API. The only way to actually retire a name is to bump the whole bridge version, and that only ever changes what gets built next, never what already exists.

It's a small table in one file. It's also, as far as I can tell, the real mechanism behind a sentence that's easy to put on a pricing page and hard to make true: your tools keep working. Not a promise. A versioning rule that treats every exported file as something that has to survive, unmodified, on hardware we will never see again.

I'm building FOKL on that rule on purpose now, instead of relearning it the same way twice.

FAQ

How do you version an API without breaking existing clients?

Treat a method name as something that can be superseded but never withdrawn. When a method is renamed, the old name is kept resolving — routed to the new behavior through a table of deprecated names checked before anything else runs — so software built against the old name keeps working. A clean break (full removal) only happens behind a new version number, and that version bump only affects what's built after it, never what already exists.

Why can't offline or exported software just receive a bug-fix update?

A normal web app's client and server ship together: the next page refresh fetches the new code, so a breaking server-side change is invisible to the user. A tool that's exported, saved, or run fully offline has no next refresh — it's a static file calling an API by name, with no mechanism to pull in a newer version of itself. If the API it's calling changes incompatibly, the tool simply stops working, silently, with nobody notified.

What does it mean for an API method to be "superseded" rather than removed?

Superseding a method means a newer name takes over as the recommended way to call that capability, while the old name keeps being honored indefinitely — typically by resolving it to the same underlying behavior through an alias table. Removal, by contrast, deletes the old name outright and breaks any caller still using it. Superseding trades a small amount of ongoing maintenance (keeping the alias table) for never breaking a client you can no longer reach to fix.

What is a postMessage bridge API, and why does its versioning matter more than a normal REST API's?

A postMessage bridge is how code running in a sandboxed iframe — which has no direct network access or shared storage with its host — talks to the page that embeds it, by posting named messages back and forth. Because the iframe's content can be a static file saved long before the bridge code changes, the bridge's method names function like a permanent contract: the embedded file keeps calling whatever name it was written against, potentially for years, with no way to be told the name has changed.

Made with FOKL — little apps your family keeps.