Cheap to run
~$0 when idle, tiny fractions of a penny per execution. Containers-per-user are a non-starter.
A visual essay
Why ordinary web software strands the long tail of individual needs, why LLMs change the economics of extension, and what it takes to run untrusted code safely.
Most web software is static. Developers serve the head of the demand curve and leave a long tail of individual needs unmet — because every added feature makes the product worse for everyone who doesn’t need it.
Hover or drag the threshold. Moving it right adds niche features, serving more users but raising complexity for everyone.
The head of the curve gets the roadmap. The tail gets workarounds, spreadsheets, or nothing. As more features are crammed in, the interface accretes buttons, toggles, and modes that most users never wanted. The product becomes worse for the majority in order to satisfy a minority.
LLMs excel at building Software for One — personal tools custom-fit to a single workflow. The result is software with a battle-tested core that is endlessly extensible just by asking.
“Agents make it easy to build personal tools for yourself or your team. But deploying, securing, and sharing that software is still far more complicated than creating it. A cloud built for small software could remove that complexity and make bespoke tools as easy to share with a colleague as a Google Doc.”— Pete Koomen, Y Combinator on “Small Software”
In the past year, users suddenly gained the ability to speak code into existence. Most existing software can’t leverage that. Pi does. But most pluggable software today is local professional tooling — AI agents, IDEs, game mods, Blender add-ons — with a high barrier to entry.
The web is the most successful software distribution system in the world. It shouldn’t be left behind.
LLMs lower the cost of authoring extensions. Modern sandbox primitives lower the cost of deployment and provide security boundaries. Build a solid, accountable core, and let users safely extend it by having an LLM fill in the missing pieces.
// onFave: if wordCount > 4000, queue to e-reader
export default async function onFave(article, { dispatch }) {
if (article.wordCount > 4000) {
await dispatch.toEreader(article);
}
}
Webhooks force the user to build and operate an entire service, plus handle delivery, retries, and auth.
A robot extrudes the silly bits of code, hooks them into extension points, and the user can share the result with others. Instead of asking a user to build a separate service, the logic lives inside the app, governed by the same sandbox.
The extension pattern applies wherever a core product meets a diverse set of user workflows. Four places where it is especially pressing.
Pi, DeepSeek, and OpenCode already experiment with prompt-driven extensions, but the audience is still small and mostly technical.
Vibe-coded tools create maintenance, data access, audit, token-scope, and GDPR nightmares. The fix: a governed place to deploy code where no auth tokens can leak.
Extensions surface per-ticket data, kick off investigation agents, and add one-click actions like “reset quota X,” shareable with the team.
Trace waterfalls fit request/response systems, not stateful agents and durable workflows. Users need custom visualizations, ingestion transforms, alarm scripts, and deploy-time checks.
Rather than bloating the harness, agents can provide stable hooks for tools, commands, events, and UI. A request becomes a small TypeScript extension, reloads in place, and can be shared.
“…nearly everything is an internal plugin — 68 of them — which means any behavior can be disabled and the plugin APIs are properly dogfooded.”— OpenCode, on building with internal plugins
Obsidian proves the power of extensibility — and its cost. You must trust every plugin. That works for low-stakes notes, but falls apart for customer records, financial transactions, or private messages.
Click a threat to see how it breaks the dream.
Executing arbitrary user code raises a wall of threats. The dream of effortless customization meets the reality that one malicious or careless snippet can harm every other tenant. The wall is not a reason to give up; it is the specification for the primitive we need.
Since 2007 — before S3 and EC2 were even a year old — Salesforce has run customer code safely at immense scale as a multi-tenant programmable platform.
@RestResource(urlMapping='/customer-health')
global with sharing class CustomerHealthApi {
@HttpGet
global static Account getCustomer() {
// Salesforce handles routing, auth, tenant isolation, execution.
// No web server to deploy.
Account a = [SELECT Id, Name, Health_Score__c
FROM Account
WHERE OwnerId = :UserInfo.getUserId()
LIMIT 1];
return a;
}
}
public class RenewalScanner implements Schedulable {
public void execute(SchedulableContext context) {
// Flag accounts with renewals in the next 30 days
List<Account> accounts = [
SELECT Id, Needs_Attention__c
FROM Account
WHERE Renewal_Date__c <= NEXT_N_DAYS:30
];
for (Account a : accounts) {
a.Needs_Attention__c = true;
}
update accounts;
}
}
// Schedule to run daily at 2 a.m.
System.schedule('RenewalScanner', '0 0 2 * * ?', new RenewalScanner());
// A modern Workers-style exported handler
export default {
async fetch(req, env, ctx) {
const { account } = await env.DB.prepare(
`SELECT id, name, health_score
FROM accounts WHERE owner_id = ?`
).bind(env.user.id).first();
return Response.json(account);
},
} satisfies ExportedHandler<Env>;
{ "crons": ["0 2 * * *"] }export default { async scheduled(controller, env, ctx) { await flagRenewalsInNext30Days(env.DB); }, } satisfies ExportedHandler<Env>;
Salesforce had to build a compiler, type system, runtime, debugger, and an educational ecosystem. The business value justified it. In 2026, we have far more options — but the core requirement remains: safely run custom logic in response to app events, within transactions.
This is the heart of the argument. An extension primitive must satisfy five properties. Each one is a constraint that turns the threat wall into an engineering target.
~$0 when idle, tiny fractions of a penny per execution. Containers-per-user are a non-starter.
Single-digit milliseconds when user code is on the request’s critical path.
CPU, memory, network, response size, log volume and rate.
Fault and security isolation: crashes, infinite loops, memory bombs, Spectre.
Hand untrusted code narrow references to approved functions. Remove ambient I/O.
With thousands or millions of users running snippets, per-user containers are economically impossible. Idle cost must be near zero and per-execution cost microscopic. Memory overhead per tenant directly determines machine density.
A popular getting-started guide once told users to deploy:
while True:
print("hello world!")
A brand-new app instantly started spewing millions of log lines per second, forever. Without limits on CPU, log rate, and memory, one tutorial can devastate a platform.
The subtlest property is safe action. The same task — “fetch one approved email” — can be exposed four different ways. Try each model and see if you can leak the credential.
export default function shouldWeOrderPizzaTonight(data: Input): boolean {
const haveFoodAtHome = data.fridge.hasIngredients;
const haveEnergy = data.body.checkCapacity;
const haveTime = !data.schedule.isTight;
return true;
}
Four broad approaches, presented as an honest comparison. The same five properties matter for agent execution platforms too: running logic on behalf of a user you cannot trust is the same problem.
| Technology | Cheap | Fast start | Limits | Isolation | Capabilities |
|---|
Lua, QuickJS, or a custom language. Flexible and easy to reason about, but you build the runtime and limits yourself.
Lua, QuickJS, or roll-your-own. The Salesforce path: full control, full responsibility.
Google-hardened JavaScript engine. Cloudflare Workers, isolated-vm, Rivet secure-exec, celld.
Firecracker, libkrun, AWS Lambda MicroVMs, @deno/sandbox, smolvm, Tensorlake, Daytona. Near-VMs under a second.
Blank slate with no ambient HTTP or env. Host defines capabilities. Composes with isolates or microVMs.
Where the primitive lacks a capability model, consider an object-capability protocol like Cap’n Web. The options also compose: WebAssembly can run inside a V8 isolate, and microVMs are useful for authoring and testing even when the runtime is an isolate.
Disclosure: Jeremy Morrell works at Cloudflare. This section reflects the essay’s argument that Dynamic Workers are the closest thing in 2026 to a production-ready framework for extensible web apps.
Built-in tracing and telemetry primitives, so you and your users can see what code is doing.
Multi-tenant data storage without leaking auth tokens.
Actions that span minutes or days, with retries and backoff.
Users can iterate on extensions without a separate GitHub account.
Expose models inside the extension runtime with rate limits.
Transpile and test user code without a separate container.
export async function analyzeArticle(env: Env, article: Article) {
const result = await env.AI.run(
'@cf/meta/llama-3-8b-instruct',
{
messages: [
{
role: 'system',
content: 'Decide whether the supplied article talks about cute kittens.',
},
{ role: 'user', content: article.text },
],
}
);
return result;
}
import { transform } from 'sucrase';
export function transpileUserCode(source: string): TranspileResult {
try {
const result = transform(source, {
transforms: ['typescript'],
disableESTransforms: true,
});
return { type: 'success', code: result.code };
} catch (err) {
return { type: 'failure', error: String(err) };
}
}
Dynamic Workers are not the only answer, but they bundle the primitive, the storage, the execution, the observability, and the LLM in one place. That is the difference between a theoretical sandbox and a platform users can actually ship.
Platforms are hard to design, hard to run, and hard to debug. But they are worth it, because you can be genuinely surprised by what your users build.
The long tail of needs is not a niche edge case. It is the natural shape of software demand. LLMs make it cheap to address. Sandboxes make it safe. The only question left is what kind of platform you will build on top of the primitive.