The Stable Thing
Software Has Always Had a Fixed Point. We’re About to Move It.
In 1986, Joe Armstrong was given a hard problem. Ericsson needed software for its telephone switches, systems routing hundreds of thousands of simultaneous calls across Sweden. The biggest challenges? Continuity. A switch that went offline to install an update dropped every call running through it. In telecom, that’s a double whammy of bad user experience and a contractual violation.
The standard engineering answer was to make downtime short and scheduled: 3am on a Sunday. Armstrong rejected this solution. He didn’t want to minimize downtime. He wanted to eliminate it entirely.
To do that, he had to make a decision that seems obvious in retrospect but wasn’t obvious at the time: he had to decide what must never be interrupted in a running system. His answer was process state. The context each process held had to survive any change to the code around it: what it was doing, what it knew, what it was in the middle of. Everything else could be swapped. That couldn’t.
The reason this decision was hard is that most programming languages make it nearly impossible to actually do this. In a conventional system, code and state are entangled. Threads share memory. Objects hold references to methods. If you swap a module while the system is running, you create a window where old code and new code are touching the same data simultaneously. Crashes are likely to happen.
Armstrong’s answer was to eliminate entanglement entirely. In Erlang, processes don’t share memory. Each process owns its state completely. Communication happens only by passing messages. If one process crashes, it crashes alone.
That isolation made hot code loading tractable. When you update a running Erlang system, the BEAM virtual machine loads the new version of a module alongside the old one. Both versions sit in memory simultaneously. Running processes finish what they’re doing on the old version. The next time a process makes a fully-qualified function call, it gets the new version. The transition happens process by process, on each process’s own terms.
In 1998, Ericsson shipped the AXD301 switch. It contained over a million lines of Erlang. Its reported availability was 99.9999999 percent — nine nines — meaning less than one second of downtime per year. Five nines is the standard most telecoms aim for and most cloud services miss. Code was being swapped while calls ran through it.
What Armstrong had built was a system organized around a clear answer to a clear question: when everything can change, what must stay stable? Process state. Everything followed from that.
Then the web arrived, and the industry discovered it didn’t need to answer the question at all.
The web ran on servers, and servers could restart. A deployment that took two minutes at 3am was an inconvenience, but not a crisis. So instead of deciding what had to survive, engineers built infrastructure that made survival unnecessary. Blue-green deployments: run two identical environments, point traffic at one while you update the other, then flip the switch. Rolling restarts: take instances down one at a time, update them, bring them back up. Load balancers. Containers. Kubernetes.
Armstrong’s problem stopped mattering. You no longer needed to update a running system safely, because you could always spin up a new one. The question of “what must stay stable while everything changes?” quietly disappeared. Restarts were free. Stability could live outside the code entirely, in the infrastructure that surrounded it.
Armstrong’s insight became a curiosity. Erlang was deployed in serious infrastructure at WhatsApp and RabbitMQ, but stayed niche. Admired by people who understood it, but never a mainstream choice. The problem it had been designed to solve had been worked around.
The assumption this left behind went largely unexamined: that there was always a canonical implementation, and that the engineering problem was managing how carefully you replaced it. A new deployment meant a new version, and a new version meant everyone got the same thing. Feature flags pushed at the edges of this; you could change what users saw without a full redeploy, toggle a new behavior on for 5% of users, watch what happened, expand from there. LaunchDarkly built a business on making this tractable at scale. Progressive delivery gave teams finer control over rollouts.
But all of these were still organized around a fixed point. There was one true version of the software. The work was deciding who saw it and when.
Nobody asked what happened if that fixed point moved.
Until recently, the question was largely theoretical. Moving the fixed point required something that could read code, understand what it was for, and produce new code to serve the same purpose in a changed context. That capability didn’t exist. Now it roughly does, which means the question is no longer hypothetical.
A software agent improving an application based on how people use it doesn’t naturally produce a single change for all users. It produces observations about specific people in specific contexts. What one person needs from a piece of software may be genuinely different from what another needs. Preferences, workflow, history, circumstance. The agent’s output isn’t a new version for everyone. It’s a set of changes that may be just for that user.
A deployment pipeline isn’t designed for this. Pipelines were built for humans making deliberate decisions: write code, review it, test it, ship it to everyone. The pipeline assumes a single canonical output. An agent working continuously, proposing changes shaped by individual behavior, puts pressure on that assumption in a way that feature flags and canary deployments don’t resolve. Those tools let you vary who sees a version. They don’t let the version itself vary by user.
Similar to Armstrong’s problem, the question then becomes: what stays stable? If implementations and code can vary, what’s the fixed point?
Erlang’s answer was process state. The web infrastructure era’s answer was: it doesn’t matter, restarts are free. Feature flags said: the canonical codebase is stable, we just control its visibility. Each answer worked for the era it was designed for. Each one held the line somewhere different.
None of those answers fit what agents require to operate at their full capacity: proposing changes continuously, shaped by individual context, without anyone deciding what the canonical version is.
Mark Burgess encountered the same coordination problem in distributed systems and formalized it in Promise Theory in 2004. His answer was that you couldn’t impose a shared implementation on autonomous agents. Each agent could only make promises about its own behavior. Coherence emerged from those promises, not from a central authority enforcing a single version. It’s coordination by choice, not command. Charles Simonyi spent fifteen years at Microsoft trying to build a system that stored intent as a permanent artifact and regenerated code from it automatically. The project was killed in the early 2000s. The infrastructure to make it real didn’t exist yet.
What’s changed is that the translation layer now exists. A language model can hold the context of what a user does, infer what they need, and propose changes to their instance without a human engineer in the loop for each iteration. The gap between “what this user needs” and “the code that provides it” can be closed continuously, not just at the moment of creation.
Which brings Armstrong’s question back around, in a different form. If different people are running software that has evolved differently in response to their behavior, then what the system is actually preserving isn’t the code. It’s the intent the code is meant to satisfy.
Once you treat intent as the stable thing, the rest of the system can change freely. Implementations can diverge, regenerate, adapt to context, as long as they continue to satisfy the same constraints. Code stops being the artifact you version. It becomes a local, disposable realization of something more durable.
This is what Sky Valley is building: infrastructure that treats intent as canonical and lets implementations vary. The protocol that lets agents declare what a piece of software is supposed to do. The runtime where local manifestations can diverge as long as they’re still converging on the right behavior. It’s an attempt to answer Armstrong’s question at a different level of the stack. Not what process state must survive a code swap, but what meaning must survive an implementation change.
Armstrong didn’t set out to make a philosophical argument. He set out to keep telephone calls from dropping. The philosophy came out of the constraint: when you can’t restart, you have to decide what must survive. Once he decided, everything else in Erlang’s design followed. The language, the runtime, the isolation model. All of it was downstream of one clear answer to one clear question.
The industry could avoid that question for forty years by making restarts cheap. What’s changing now is that agents introduce a constraint that restarts can’t dissolve: the assumption, built into every deployment pipeline ever designed, that someone decides when to release and that what gets released is the same for everyone. An agent that adapts software continuously to individual users doesn’t fit that box. The pipeline has no slot for it.
The answer looks the same as it did in 1986. Decide what must stay stable. Build the isolation around that. Let everything else change.
In Erlang, the unit of continuity was the process, so the stable thing was its state. In a system where software evolves per user, the stable thing has to move up a level, from state to the intent that state is serving.


