Malleable software - until the server says otherwise

A small community has spent the last several years arguing that ordinary users of software should be able to reshape and reimagine the tools that they use. One might imagine that this movement for “malleable software” would have been turbocharged by the development of AI coding tools, since building software no longer strictly requires knowing how to code. In practice, though, users modifying their own software remains vanishingly rare, and limited to experts, raising the question: why? Part of the answer is surely that it’s early. But I think a large part of the answer is that users now exist in a tech ecosystem that’s locked down in nearly every corner, with one underappreciated exception, and even that one holds only as long as the server allows.

What is malleable software?

Malleable software, as defined by Litt et al., is software that “users can reshape with minimal friction to suit their unique needs”. It allows individuals or communities to put together the functionality they need without fighting for a spot on some tech org’s engineering roadmap.

I think it’s also important to name what malleable software is not: plugins. Applications that support plugins generally offer an extremely circumscribed notion of extensibility, and allow users to modify only the aspects of the software that were deemed, by our hypothetical org, worthy of making modifiable on the roadmap.

Earlier this year, I built some software which I now recognize to be malleable - my browser extension, Mealshark. This extension gave me some MealPal features I’ve wanted for years: the ability to sort meals by % off, the cost of each meal in dollars, and a filter for new meals only, none of which I think MealPal would ever have prioritized. I’d never written a Chrome extension before, and I still don’t know how to today - luckily, your coding assistant does.

This project was only possible because MealPal has a web version of the app, and therefore I could extend it in the browser; if it were distributed mobile-only, there could be no Mealshark.

Browser extensions are the exception

The browser is the only platform where every user gets:

  • A standard, introspectable, modifiable representation of every application
  • A sanctioned means of modifying every application, without requesting the application vendor’s permission

Every other setting in modern tech fails these tests. For example:

iOS and Android apps: ❌

Mobile apps have no standardized design layer, and cannot generally be introspected or modified by code. An additional difficulty is that there’s no developer tools pane with a Network tab for mobile; importantly, you can’t see the requests apps send, and even coding assistants can only infer what they receive.

Windows and Mac OS apps: ❌

A desktop application running on these platforms is essentially compiled code drawing into a window; there’s nothing approaching a standardized representation for app content in general. The industry’s direction for these platforms is, further, toward binary signing schemes that will prevent modified applications from running at all. Mac OS already refuses to run apps whose signatures are broken by changes, and Windows increasingly pushes users to software from the Microsoft Store, which installs the software into a locked-down directory the user can’t modify.

There’s a notable exception, in the form of webview-based native apps. An example of malleable software on Windows would be the Spicetify project, which allows, among other things, customizing the UX of the Spotify application. However, the mechanism for customizing the UX is essentially taking advantage of the app’s design as a SPA web app running in a webview; the Spicetify app replaces the Spotify SPA files with its own before startup, making this exception one that actually proves the rule. And, returning to the point about the Microsoft Store - Spicetify explicitly instructs users not to use this install method because it breaks Spicetify’s functionality.

This state of affairs doesn’t leave many places for typical users to create and customize software to suit their needs. OSS built from source can offer users this opportunity, but this population more or less self-selects into irrelevance; in practice, typical users seeking to modify and extend their software tools have one place to go, and it’s the browser. Unfortunately, as more and more vendors go mobile-first and offer only limited web versions of their service or none at all, users get fewer and fewer opportunities to customize their software tools.

Keeping up with breaking changes

Historically, beyond the challenge of writing extensions by hand in the first place and adequately anticipating the DOM elements the extension code would need to handle, there was an additional problem of dev attrition. When the sites changed their designs, the selectors used by the extensions to identify page elements would stop working, and the extension would just… be broken until the developer returned to get it working again. Often, this never happened at all, as was the case for the once-popular browser extension Refined Twitter, whose archived Github repo shows this message:

This project is not maintained anymore. Twitter rewrote their website and completely broke this extension, and it’s much harder to reliably modify the new website. I also don’t have time to fix these things and no one has stepped up to do so either. It had a great run. Thanks for all the love.

In addition to routine changes to UI, migrations to systems that use randomized class names - which are common in many modern web frameworks - could easily require the developer to go back to the drawing board almost entirely with regard to an extension’s implementation; it’s not hard to imagine how these kinds of changes would lead to a lot of extension author burnout and then to zombie unsupported extensions.

In my original Mealshark post I claimed that AI would change this dynamic: that a hobby developer, or even a user with no coding background, could realistically keep an extension working through breaking changes. On this, I now have one real data point.

This summer, MealPal introduced “Pal Pricing”, a restaurant-specific discount that would show up on meals as a struck-through price, like “14 ➞ 12”. This silently broke Mealshark in a couple ways, causing it to order meals by discount percentage incorrectly and also over-report the dollar price. I happened to notice this new feature in the mobile app, and within a couple hours, Mealshark supported it. The fix touched four files and consisted of 200-odd lines, none of which I wrote; my coding assistant found the new meal_credit_discount field added to the MealPal menu response, and leveraged it to fix the ordering and the dollar price.

This mechanism generalizes. In our new world of AI coding tools, work that would have once made maintaining a hobby extension challenging against a backdrop of, y’know, life, has evaporated. Extension authors don’t need to parse unfamiliar, randomized, minified code to understand what’s different, nor read through undocumented fields in server responses; they just need to tell Claude/Codex/etc about the problem and push the fix. Even deliberate attempts at obfuscation are unlikely to pose a problem.

But the buck stops with the server

So far, we’ve only discussed the client - the parts of web applications that browsers show you, and that extensions can change. Ultimately, though, the data you see in a web application comes from the server; and if the vendor modifies the server to stop sending the data you need, AI can’t help you restore your extension’s functionality.

At risk of giving the game away, here’s Mealshark’s biggest vulnerability: when you open the web app to choose your lunch, MealPal sends a single response containing the entire menu - 1000ish restaurants in New York, all at once. The web app does paginate the list of meals it displays, but that pagination is, for now, client-side only.

Now, suppose MealPal paginated the menu response, sending 25 restaurants at a time. In order to implement its filtering and ordering features, Mealshark would have to programmatically request all the pages before it could display anything - but MealPal’s terms expressly forbid the use of “automated means to access the Site.” AI wouldn’t be of any help with this problem; the data the extension needs to function simply wouldn’t be there anymore. (Strictly speaking, the terms also forbid using “modified versions of the Site,” a clause that would cover the use of any browser extension at all. But this one is unenforceable in practice - MealPal’s servers can’t see what my browser displays, but they can definitely see the requests it sends.)

Litt et al. noted in Malleable Software that “browser extensions can’t modify server-side behavior, severely limiting the features they can provide” - but really, I think this understates the dynamic. Even when a useful piece of malleable software already exists in the browser, a simple server-side change can - straining the malleability analogy - flatten it like play-doh at any time. Beyond the tests identified earlier - that malleable software requires an introspectable representation and a way to modify it - the vendor whose tools you’re modifying has to send you the data. The browser gives us the first two, but this third requirement is up to every individual company, and it’s not a gap AI can close.