Source-last programming

edit

Abstract. Perhaps to build systems that are malleable and end user programmable we need to rethink the relationship between runtime and development artifacts. It is our opinion that the concept of source code itself was the original sin that drove a wedge between user and developer.

Most existing programming systems are format-first: a canonical saved representation — `.ipynb`, an image dump, a document schema that the system loads. Lopecode is source-last: there is no external source code or canonical serialized representation; the only canonical representation is the live executing system. When source code is needed, functions are decompiled on demand starting from Function.prototype.toString(). Serialization becomes a projection to one of many formats: a standalone HTML file, a JavaScript IIFE or an ATProto PDS. Format-independence is a consequence of runtime-primacy. Furthermore, we claim runtime-primacy also leads to simpler implementations of malleability and liveness, by admitting a plurality of non-source based editing surfaces.

We share three field episodes where Lopecode's format agnosticism shone: shipping a tool into a locked-down corporate environment; liberating a running program from a notebook SaaS; and freezing an AI-co-created music jam into a document shared over WhatsApp.

edit

Tom Larkworthy — submission to LIVE 2026.

edit

1. Ship the code to the data

edit

A business analyst in a regulated industry, in another continent, could not open a large CSV export with their preferred tool, Excel. We knew almost nothing about their environment except that it was strict: corporate machines, no installing software, and data compliance. We built a small tool that trims columns from large CSVs, as a Lopecode notebook, and sent the single HTML file over Slack. They double-clicked it. The tool ran offline in their browser, and they were able to reexport a trimmed CSV that could be loaded by Excel.

edit

Nothing about the tool is interesting. What is interesting is that it is actually very hard to share a program to non-programmers in 2026. Native binaries and cloud services are not safe in corporate environments. The browser is an ideal runtime because it is sandboxed and present on every operating system. A single HTML file does not require cross-origin requests, so it can be double-clicked and it just works. So a pragmatic option to distribute code is a self-enclosed file that can travel on email and instant messenger.

edit

CSV column chooser is a copy of the actual tool shared

edit

2. Runtime-first, not format-first

edit

Most programming systems are format-first: a save format is the canonical representation, and the live system is a runtime that loads it. Jupyter loads .ipynb. Smalltalk saves and loads to its image. A browser page loads HTML. Lopecode inverts the arrangement in the pursuit of liveness and malleability. The canonical representation is the live runtime: a graph of modules containing pure JavaScript functions, executed by a reactive scheduler. When a serialized form is needed, it is computed on demand by reflection. Because no format is canonical, the same runtime can be projected to different serialized representations.

Make the runtime the source of truth and serialization becomes a projection, so format-independence follows. We call the design source-last: source code still exists, but it is recovered last, on demand, from the running system, rather than maintained as the canonical artifact.

The same arrangement applies to program editors as well. Since the live runtime is the single thing every tool reads and writes, editing surfaces specialize and coexist: editor-5 edits cells as source; editable-md makes rendered prose directly editable; and sticky (§Copying the live system), a higher order UI lens that transforms user manipulations into function updates. All three are unprivileged userspace modules.

edit

Try editable-md. Click any paragraph of this essay: it opens in a live markdown editor. The prose is cells, and the editor is a userspace module riding in the same file. If you open the code editor as well, you will notice that changing and committing (SHIFT + ENTER) will update the other view.

edit
format-first save format (canonical) runtime (must conform) one format · runtime lags it runtime-first (Lopecode) live runtime (canonical) HTML file JS IIFE ATProto formats are projections · plural, downstream
edit

3. A cell is a function that carries its source

edit

Here is a simple Lopecode program. Three cells:

  1. constant holds a number

  2. fun holds a function

  3. result applies one to the other, implying both are dependencies.

Edit constant or fun and result recomputes, spreadsheet-fashion. The reactive model is Observable's JavaScript in Observable.

edit
constant = 31
close
outputs: result, cellSource
constant = 31
fun = ƒ(x)
close
outputs: result, cellSource
fun = x => x * 2
result = 62
close
inputs: fun, constant outputs: cellSource
result = fun(constant)

What matters for this essay is what a cell is made of. A cell is stored as a pure JavaScript function from its dependencies to its value, and JavaScript functions carry their own source [TC39 2018]. The block below shows what happens when the live cell's definitions are stringified with toString.

lookupVariable('constant', ...)._definition.toString()

> function _constant() {return (31);}
lookupVariable('fun', ...)._definition.toString()

> function _fun() {return (x => x * 2);}
lookupVariable('result', ...)._definition.toString()

> function _result(fun,constant) {return (fun(constant));}

That one call, Function.prototype.toString(), is the reflective interface Lopecode builds on. The runtime does not keep the text you typed anywhere; when source is needed to edit or to export, it is recovered from the executing function.

Note, recovered functions do not contain closure variables. toString() cannot see captured variables but due to the reactive runtime design a cell closes over nothing; everything it uses arrives as a parameter, so the recovered source is the complete definition.

edit

Try it. Ensure Edit mode in the burger menu is on, and click edit under fun to open editor-5's source editor and change the code to (x) => x * 3. Note result recomputes, and the decompiled listing refreshes.

edit

toString() only recovers the low-level compiled JavaScript, not the high level notebook-syntax text as the author wrote it. The observablejs-toolchain is lensed [Foster et al. 2007], so the ill-posed problem of decompilation [Kell & Stinnett 2024] is avoided by construction. The known failures of this property are listed in §Problematic examples.

edit

4. The runtime is modular

edit

The coarse unit of composition in the reactive runtime is the module, a namespace of cells. It is visualized as a notebook, and a single runtime can contain many notebooks. A running system is a set of modules importing values from each other. Imports may be mutually recursive between modules; the cell-level dependency graph stays acyclic, which is what keeps recomputation well-defined.

The single HTML rendering is one mapping of that structure, and §Formats are mappings from the runtime covers the others. You can inspect the live module graph of this very system with module-map, and the fine grained cell interdependancies with cell-map.

edit

5. Copying the live system

edit

The burger menu at the top of this pane offers Save in place, Download, Edit mode and Fork. Inline works too: download a copy of this essay, or fork it into a fresh browser tab. Copies carry all code and asset changes, the prose, the tooling, and the runtime without external build steps or internet connectivity. However, runtime values are not typically serialized.

edit
edit

[Horowitz & Heer 2023] identify that the lack of state persistence is the primary reason why Observable notebooks are not a "Live, Rich, and Composable Programming System Beyond Static Text". Lopecode is able to offer opt-in value persistence because there is no external source code.

The slider above is wrapped in sticky, an imported userspace function. On user manipulation, sticky parses its containing cell's definition with acorn and rewrites the persistence argument to the current value. In essence, storing state in its function definition. Reflective exports then propagate that state onwards.

edit

Try it. Drag the slider above, then toggle the cell editor. The second argument of sticky(...) holds the value you just set. Close the editor, drag again, reopen, the source rewrites itself on every slider change.

edit

sticky demonstrates that a single cell definition can be interpreted in multiple languages. When viewing the source of the cell through editor-5 we manipulate using a bespoke higher level reactive language, Observable JavaScript. When sticky mutates its own container, it uses the lower level JavaScript language that can be parsed with an off-the-shelf JavaScript parser, Acorn.

edit
authoreditor-5observablejs-toolchainobservable-runtime-v6stickyacorn patches the slottypes sticky(Inputs.range(...), 50)compile (high → low)define(function _dial(sticky, Inputs) { … 50 … })drags the slider to 83toString() ⇒ function _dial(sticky, Inputs) { … 50 … }swaps in function _dial(sticky, Inputs) { … 83 … } — silent, no recomputeopens the celltoString() ⇒ function _dial(sticky, Inputs) { … 83 … }decompile (low → high)sticky(Inputs.range(...), 83)shows sticky(Inputs.range(...), 83)authoreditor-5observablejs-toolchainobservable-runtime-v6sticky
edit

Every arrow above runs through the reflective waist. Authoring is high-level: notebook syntax is compiled to a plain JavaScript function and evaluated into the runtime. sticky operates entirely at the low level: on a committed change it recovers its own cell's source with toString(), patches one literal with acorn, and evaluates the patch back — the runtime never recomputes. When the author next opens the cell, the editor recovers the low-level source and decompiles it to notebook syntax, updated literal included. The compiler/decompiler pair is a lens in the sense of the bidirectional-programming literature [Foster et al. 2007] — the construction Cambria applies to live document schemas [Litt et al. 2020]: the executing function is the concrete source of truth, notebook syntax is one view, and edits on either side round-trip. The decompilability invariant of §A cell is a function that carries its source is the lens law holding across the whole runtime; §Problematic examples lists where it does not.

Decompilation is prevalent in the games modding community which is end user programming in the wild. Why not elevate the technique to be the primary method of program editing? Lopecode is a system that follows through on this idea.

edit

6. Formats are mappings from the runtime

edit

Lopecode currently maintains three mappings. Each is a userspace module, and they share nothing with each other beyond the reflection described in §A cell is a function that carries its source.

edit

6.1 HTML: the document mapping

edit

The HTML mapping stores each unit of the module graph as a <script type="text/plain"> block: one block per module holding its decompiled source, one MIME-typed block per file attachment, and a bootconf.json naming what to boot. A short bootloader at the top starts the Observable runtime and resolves imports from the embedded blocks instead of the network. The file is plain text, diffs cleanly under git, and opens from file:// with no server.

edit

This essay inspecting its own container — every <script type="text/plain"> block in the file you are reading (114 blocks):

idmimeencodingbytes
https://raw.githubusercontent.com/observablehq/notebook-kit/6c2ec69e1ac30dd329789524a849578b2df17945/src/styles/global.csstext/cssutf-84,184
https://raw.githubusercontent.com/observablehq/notebook-kit/6c2ec69e1ac30dd329789524a849578b2df17945/src/styles/inspector.csstext/cssutf-81,555
https://raw.githubusercontent.com/observablehq/notebook-kit/6c2ec69e1ac30dd329789524a849578b2df17945/src/styles/highlight.csstext/cssutf-8565
https://raw.githubusercontent.com/observablehq/notebook-kit/6c2ec69e1ac30dd329789524a849578b2df17945/src/styles/plot.csstext/cssutf-8108
https://raw.githubusercontent.com/observablehq/notebook-kit/6c2ec69e1ac30dd329789524a849578b2df17945/src/styles/index.csstext/cssutf-8271
https://raw.githubusercontent.com/observablehq/notebook-kit/6c2ec69e1ac30dd329789524a849578b2df17945/src/styles/theme-ocean-floor.csstext/cssutf-8148
https://raw.githubusercontent.com/observablehq/notebook-kit/6c2ec69e1ac30dd329789524a849578b2df17945/src/styles/abstract-dark.csstext/cssutf-8817
https://raw.githubusercontent.com/observablehq/notebook-kit/6c2ec69e1ac30dd329789524a849578b2df17945/src/styles/syntax-dark.csstext/cssutf-8369
file://syntax.csstext/cssutf-8804
es-module-shims@2.6.2application/javascriptbase64+gzip20,166
@observablehq/runtime@6.0.0application/javascriptbase64+gzip6,554
@observablehq/inspector@5.0.1application/javascriptbase64+gzip6,998
@tomlarkworthy/at-loginapplication/javascriptutf-842,551
@tomlarkworthy/at-writeapplication/javascriptutf-899,571
@tomlarkworthy/atprotoapplication/javascriptutf-89,607
@tomlarkworthy/bootloaderapplication/javascriptutf-8332,875
@tomlarkworthy/butter-synthapplication/javascriptutf-834,127
@tomlarkworthy/csv-column-chooserapplication/javascriptutf-812,065
@tomlarkworthy/editable-mdapplication/javascriptutf-833,956
@tomlarkworthy/lopecode-live-2026application/javascriptutf-862,470
@tomlarkworthy/lopepage-2application/javascriptutf-871,480
@tomlarkworthy/module-mapapplication/javascriptutf-828,512
@tomlarkworthy/robocoop-5application/javascriptutf-816,994
@tomlarkworthy/save-in-placeapplication/javascriptutf-810,278
edit

The stored form of this very module, as it sits in the HTML mapping (first 350 characters). It goes stale as you edit and is refreshed on the next save, because the block is a projection of the runtime:

const p0 = function _anonymous(md) {return (md`# Source-last programming`);};
const _abstract = function _anonymous(md) {return (md`> **Abstract.** Perhaps to build systems that are malleable and end user programmable we need to rethink the relationship between runtime and development artifacts. It is our opinion that the concept of source code its…
edit

Try it. Edit the title cell, the stored block above does not change: the runtime has moved and the projection is stale. Now Fork from the burger menu (or the inline link in §Copying the live system): the fork is written from the runtime, so it opens carrying your edit, reflected in the serialization here.

edit

6.2 ATProto: the record mapping

edit

The runtime graph maps cleanly onto ATProto. A record of type com.lopecode.bundle carries an array of file entries, pointers to MIME-typed blobs.

The userspace module atproto allows you to serialize and publish the live notebook into the decentralized network directly. The base synthesizer used in §The jam: serializing a moment was fetched from such a record. A web proxy exists for convenient access without a special reader at lopecode.com, but it is also possible to fetch modules directly from the network.

edit

6.3 IIFE: an unloader for the HTML

edit

The exporter's Copy To JS renders the runtime as a single immediately-invoked script expression on the clipboard. This is an unloader for the HTML mapping: pasted into any page that will execute a script, it reconstructs the whole environment inside that page, bringing a live editable runtime into an origin we do not control. Content security is discussed in (§Problematic examples).

edit
fork notebook options
edit

Try it. Click 'Copy as JS', open maps.google.com, open the developer console and paste.

edit

7. Liberation: exporting a program whose source you cannot see

edit

The reflective interface also works on runtimes booted by someone else. ObservableHQ.com is the hosted notebook service Lopecode grew out of. Notebooks there are compiled on Observable's servers; the source of record lives in their database, and the browser only ever receives the compiled program. Observable's own export paths use privileged knowledge of that source: the embed API is a server endpoint, and the runtime export is a multi-file bundle of compiled code that needs a local webserver to open and contains no source at all. What you get is an embedding. It runs, but it carries no editors and cannot export itself again.

edit

The exporter-3, also published on Observable as exporter-3, takes the reflective route. Imported into any notebook on the platform, it scans the live runtime in the page, decompiles what it finds, and writes a single Lopecode HTML file. We have no access to Observable's stored source and do not need it. The export is transitive: an artifact made by reflection contains the exporter's own machinery, so it can re-export, you can even export exporter-3 with itself. The copy is then independent of the platform. For larger extractions — several notebooks, their file attachments, a framing UI — jumpgate drives the same reflection with more tooling for composing arbitrary mixtures of modules; it is how the content repositories behind this essay are maintained.

Exporter-3 liberates a copy; the hosted original remains. We can consider exporter-3 an example of Adversarial Extension [Shank & Reed 2025].

edit

8. The jam: serializing a moment

edit

I shared a vibed audio notebook in a session with a music teacher, a domain expert, not a programmer and their polite verdict was that it was basic. So together we asked the in-runtime coding agent for richer sounds. Live, it wrote new instruments and effects, with presets, as extensions to the existing audio application. The feedback was immediate and audible; the teacher directed, the agent programmed. When the session ended we saved the butter-synth and shared a copy over WhatsApp as a memento.

edit

The copy is the point. The agent's contributions were cell definitions, so decompilation captured them exactly as it captures human-written cells: the exported file contains the new effects chain, still live. The version bundled in this essay is the one saved that day — diffing it against the ATProto butter-synth shows what the agent added: a tape-saturation stage, a chorus, reverb pre-delay, and a dub delay it titled "Dub Echo (Safe from Harm)", named after the teacher favourite electronic band Massive Attack whose sound was being chased. Play it.

A recording of the session would have captured the sound; the document captured the instruments. To be precise about what survives: definitions and declared state (writable file attachments) serialize; transient values do not — they recompute on boot, unless deliberately promoted into a definition, as the slider in §Copying the live system does. Ephemeral, machine-generated code became a durable artifact because serialization reads the runtime, and the runtime is where that code lived.

edit

9. One bundle: runtime, editors, agent, application

edit

robocoop, the agent used in the jam, executes inside the runtime as a dataflow program: it reads program state as well as code, and modifies cells through the same reflective interface the human editors use. This inverts the usual topology of AI-assisted programming. A coding harness such as Claude Code lives in the developer's environment and operates on source files, and the application ships separately, without it. Here the runtime, the editors, the agent harness and the application are a single bundle: what ships is an entire snapshot of an application and the application's development environment.

The consequence is personal histories. Every copy is a complete development environment, so each copy can evolve independently of any canonical upstream. The music teacher's copy of the jam contains the new instruments and the means — editors, agent, exporter — to keep changing them, independently of us and of any server. Among this document's background jobs is a change recorder, so a copy's edits are logged and replayable — version history kept inside the artifact itself, a direction Backstitch is also pursuing for the Godot editor [Ink & Switch 2026]. Copies diverge into lineages owned by their holders; malleability survives distribution because the toolchain travels inside the artifact.

The corollary is that the agent is a per-artifact composition decision, not a platform property. The tool in §Ship the code to the data went into a regulated environment carrying no agent. The jam carried one, because a generative collaborator was the point. Match what rides along to the sensitivity of the destination.

edit

10. The thin waist

edit

What is the irreducible, non-userspace core? Below the line sit the browser, es-module-shims for import interception, the Observable runtime (6.5 KB) and a bootloader; a minimal Lopecode file is about 48 KB. Everything else demonstrated in this essay is userspace. The interface between the two layers is narrow, in the manner of the Internet's hourglass [Beck 2019], and its reflective half is a single web standard: Function.prototype.toString(). The waist is specified: the stage-4 toString revision requires the returned string to be the function's actual source text [TC39 2018], and the same specification names the conditions under which a host may withhold it, a limit we return to in §Problematic examples.

edit
userspace — loosely coupled, replaceable modules open @tomlarkworthy/editor-5 editor-5 open @tomlarkworthy/editable-md editable-md open @tomlarkworthy/sticky sticky open @tomlarkworthy/module-map module-map open @tomlarkworthy/cell-map cell-map open @tomlarkworthy/exporter-3 exporter-3 open @tomlarkworthy/atproto atproto open @tomlarkworthy/robocoop-5 robocoop-5 open @tomlarkworthy/local-change-history local-change-history Function.prototype.toString() browser JS engine + Observable reactive runtime the platform: standard, not ours, not moldable from within
edit

The narrow waist pays twice. First, it lets tooling be uncoordinated. editable-md (the prose editing in this page), editor-5 (the code editor behind Edit mode), the exporter and the agent do not know about each other. Each reads and writes the runtime through the same reflective interface, so a new editor is a module you import, not a fork of the system. Second, the waist is a web standard rather than a private VM interface, so the artifact inherits the browser's backwards-compatibility discipline. Our first, embarrassing export from January 2025 still opens.

In the vocabulary of BootstrapLab [Jakubovic & Petricek 2022]: the platform is the browser plus the Observable runtime; the substrate is the script-block container plus the reflection SDK; everything above is product. Lopecode did not ascend from a low-level instruction set — it inherited a high platform and closed the loop by making the producer, the exporter, ordinary userspace modules.

edit
edit

The form of this submission follows [Edwards et al. 2019]. That paper criticizes LIVE-style venues for work "presented informally, through screencasts", lacking related work, and proposes the interactive essay, evaluated by inquiry, as the remedy — while naming the archival fragility of web essays as an open difficulty, "easier to address if they are self-contained". This essay is submitted as evidence on that point: an interactive essay that is self-contained by construction, carries its own tooling, and re-exports itself. We adopt their author guidelines, including the requirement for problematic examples (§Problematic examples).

edit

[Jakubovic et al. 2023] define a programming system as "an integrated and complete set of tools sufficient for creating, modifying, and executing programs", which is the register in which Lopecode asks to be judged: it is not a language and not a library. Their design-space maps observe "a conspicuous blank space at the top-right" where high self-sustainability meets high notational diversity; Lopecode sits toward that corner, re-serializing itself while its notation spans prose, code, widgets and whole userspace UIs. [Jakubovic & Petricek 2022] define self-sustainability as dissolving the product/source/producer distinction, and reach it by ascending from a minimal substrate. Their persistence, notably, was a manual walk of the state graph to a JSON file — "reminiscent of the image-based persistence in Smalltalk, though it is frustratingly manual". The exporter is Lopecode's answer to exactly that problem, and it adds the axis their account leaves open: the product is a single runtime-free file, so persistence doubles as dissemination.

edit

The mechanism belongs to the reflection literature. [Smith 1984] introduced procedural reflection — a program able to represent and act on its own state. [Maes 1987] named the general property computational reflection and reified it as metaobjects. [Kiczales et al. 1991] turned reflection into an engineering practice: expose the implementation to userspace as a metaobject protocol. Lopecode's runtime SDK is a metaobject protocol in that engineering sense — the editors, the exporter and the agent are metaprograms written against it — though the reflection on offer is deliberately coarse: whole definitions are read and written, and there is no intercession in the scheduler.

edit

The exporter is a mirror in the sense of [Bracha & Ungar 2004]: a meta-level facility separated from the base program (their stratification) that reifies the runtime's own categories — modules, cells and attachments map one-to-one onto script blocks (their ontological correspondence). Bracha and Ungar motivate mirrors by "significant advantages with respect to distribution, deployment and general purpose metaprogramming"; a mirror whose output is a deployable artifact takes that motivation literally.

edit

The comparison Lopecode invites most is the Smalltalk image [Ingalls 1981]. An image persists a whole live world, and so does a Lopecode file. The differences are the point: an image is an opaque memory dump bound to its VM, where the Lopecode mapping is legible text bound to a web standard; and Smalltalk is imperative message-passing where Lopecode is reactive dataflow. Smalltalk remembers values, Lopecode only exports code. We cite Smalltalk for image persistence and total moldability, not as an architectural analogy. Squeak sharpened the self-description end of that tradition — a Smalltalk whose virtual machine is written in itself [Ingalls et al. 1997]; its producer is a translator that emits a VM, where Lopecode's producer is an exporter that emits a document.

edit

[Miranda 2025] is the closest recent precedent: single HTML files that modify and save themselves. In our vocabulary his file is the canonical artifact — format-first — where Lopecode's file is one projection among three. [Klokmose et al. 2015] made the DOM itself the shared persistent substrate; again the persisted structure is the document. The mechanism specific to Lopecode is that the persisted form is decompiled on demand from live functions, which is what makes the projections plural and the export transitive (§Liberation: exporting a program whose source you cannot see).

edit

[Litt et al. 2025] argue for software that users reshape at the point of use, and diagnose the wall between users and "engineering teams at distant corporations". A document that carries its own editors is one concrete form of point-of-use agency, and §Ship the code to the data is a field report of it crossing an actual corporate wall. [Shank & Reed 2025] name the adversarial conditions live programming meets outside the lab; our findings on hosts that defend themselves (§Problematic examples) are the same territory approached from the distribution side. [Horowitz & Heer 2023] name persistence as the quality separating rich in-notebook widgets from programming: interactions with a rendered tool "cannot be 'saved' back to the notebook, and their effects will always disappear when the notebook is reloaded". A definition that is data a cell can rewrite (§Copying the live system) supplies that quality from userspace.

edit

Outside research systems, decompilation is already how shipped software gets reopened. Minecraft's modding ecosystem stands on decompiling and re-mapping an obfuscated binary — the libre yarn mappings exist for exactly this [FabricMC 2016] — and the Super Mario 64 decompilation reconstructs buildable source from a ROM [n64decomp 2019]. Those communities work for years to recover what the vendor withheld. A source-last artifact withholds nothing: decompilation here is the system's ordinary read path, not an act of reverse engineering (§A cell is a function that carries its source).

edit

12. Problematic examples

edit

Following the guideline in [Edwards et al. 2019]: problems in roughly the same number as benefits.

Not everything round-trips. Serialization captures definitions and declared state. State accumulated outside a file attachment reboots to its definition, not to its moment. The sticky idiom of §Copying the live system narrows the gap by rewriting chosen view state into the definition, but only for JSON-serializable values with commit semantics.

Decompilation has edge cases. toString() recovers compiled JavaScript; the inverse mapping back to notebook syntax is engineered, not free. Agents that write arbitrary low-level definitions can create undecompilable expressions. A reactive test guards the decompilability invariant to warn the agent, but the agent might ignore the warning. The web platform can also decline: the specification's HostHasSourceTextAvailable hook lets a host withhold source text entirely [TC39 2018].

No closures means not general JavaScript. The recovered source is complete only because cells close over nothing (§A cell is a function that carries its source). toString() cannot capture a closure environment, so the technique does not extend to programs that use closures for state — which is most idiomatic JavaScript. Source-last recovery is a property of the closure-free cell shape the Observable Runtime encourages, not of the language.

The browser has its own limitations. Arbitrary HTTP is subject to CORS, and raw TCP, processes and the local file system are unavailable, so whole classes of useful programs cannot be expressed. The same sandbox is why the file is a viable distribution format at all (§Ship the code to the data): the dangerous facilities of remote code execution are neutered by the environment itself.

The moldability gradient is steep. Changing a value or a paragraph is simple. Replacing the exporter or the editor requires understanding the runtime SDK. We have no evidence yet that a non-programmer can cross that gradient unaided. Agents have a habit of glitching themselves when attempting it.

A document that runs code is a phishing shape. The same properties that carried the tool of §Ship the code to the data through a corporate boundary could carry a malicious payload. Provenance and signing are unsolved in Lopecode. Plain-text legibility is a partial mitigation, and some email gateways rightly quarantine HTML attachments.

Adversarial hosts can protect against injection. The injection direction of §IIFE: an unloader for the HTML works on cooperative or self-owned pages. Commercial sites defend themselves: when we injected into Google Trends, the page disabled itself even with content-security policy turned off.

Offline-first is manual labour. Every dependency must be vendored into the file. We chose openness over conceptual integrity here, and the price is that adopting a library is a deliberate act, not an import statement.

edit

13. The three questions

edit

LIVE asks three questions of systems submissions. In brief:

What did we discover that other researchers should know about? Source-last design. When the live runtime is canonical and every cell carries recoverable source, serialization becomes a reflective projection. Distribution (§Ship the code to the data), cheap copies (§Copying the live system), format plurality (§Formats are mappings from the runtime), liberation (§Liberation: exporting a program whose source you cannot see), the capture of machine-generated code (§The jam: serializing a moment) and co-shipping the development environment itself (§One bundle: runtime, editors, agent, application) stop being separate features; they fall out of one mechanism.

What previous systems are similar? Image persistence in Smalltalk and Lisp; hosted reactive notebooks (Observable); document-first self-modifying files (Miranda, Webstrates); self-sustainable systems (BootstrapLab). §Related work details where each differs — in one line: those persist a canonical artifact, we project a canonical runtime.

Where are the limits? §Problematic examples: transient state does not round-trip, decompilation has edge cases, the moldability gradient is steep, the trust story is unsolved, adversarial hosts defend themselves, and offline-first vendoring is manual.

edit

References

edit
  1. Edwards, J., Kell, S., Petricek, T. & Church, L. (2019). Evaluating programming systems design. PPIG.
  2. Jakubovic, J., Edwards, J. & Petricek, T. (2023). Technical Dimensions of Programming Systems. The Art, Science, and Engineering of Programming.
  3. Jakubovic, J. & Petricek, T. (2022). Ascending the Ladder to Self-Sustainability: Achieving Open Evolution in an Interactive Graphical System. Onward!.
  4. Bracha, G. & Ungar, D. (2004). Mirrors: Design Principles for Meta-level Facilities of Object-Oriented Programming Languages. OOPSLA.
  5. Ingalls, D. (1981). Design Principles Behind Smalltalk. BYTE.
  6. Miranda, D. (2025). Single HTML Files as Self-Modifying Web Applications. LIVE 2025.
  7. Shank, C. & Reed, O. (2025). Live Programming in Hostile Territory. LIVE 2025.
  8. Klokmose, C.N., Eagan, J.R., Baader, S., Mackay, W. & Beaudouin-Lafon, M. (2015). Webstrates: Shareable Dynamic Media. UIST.
  9. Litt, G., Horowitz, J., van Hardenberg, P. & Matthews, T. (2025). Malleable Software: Restoring User Agency in a World of Locked-Down Apps. Ink & Switch.
  10. Beck, M. (2019). On the Hourglass Model. Communications of the ACM 62(7).
  11. Smith, B.C. (1984). Reflection and Semantics in LISP. POPL.
  12. Maes, P. (1987). Concepts and Experiments in Computational Reflection. OOPSLA.
  13. Kiczales, G., des Rivières, J. & Bobrow, D.G. (1991). The Art of the Metaobject Protocol. MIT Press.
  14. Ingalls, D., Kaehler, T., Maloney, J., Wallace, S. & Kay, A. (1997). Back to the Future: The Story of Squeak, a Practical Smalltalk Written in Itself. OOPSLA.
  15. Ficarra, M. (ed.) (2018). Function.prototype.toString Revision (stage-4 ECMA-262 proposal). Ecma TC39.
  16. Horowitz, J. & Heer, J. (2023). Live, Rich, and Composable: Qualities for Programming Beyond Static Text. PLATEAU.
  17. Foster, J.N., Greenwald, M.B., Moore, J.T., Pierce, B.C. & Schmitt, A. (2007). Combinators for Bidirectional Tree Transformations: A Linguistic Approach to the View-Update Problem. ACM TOPLAS 29(3).
  18. FabricMC contributors (2016). Yarn: libre Minecraft mappings. GitHub.
  19. n64decomp contributors (2019). A Super Mario 64 decompilation. GitHub.
  20. Ink & Switch & Endless Access (2026). Backstitch: real-time collaboration and version control for Godot. public alpha.
  21. Kell, S. & Stinnett, J.R. (2024). Source-Level Debugging of Compiler-Optimised Code: Ill-Posed, but Not Impossible. Onward!.
  22. Litt, G., van Hardenberg, P. & Henry, O. (2020). Project Cambria: Translate Your Data with Lenses. Ink & Switch.
edit
cite = ƒ(key)
edit
bibliography = Object {edwards2019: Object, jakubovic2023techdims: Object, jakubovic2022ladder: Object, bracha2004mirrors: Object, ingalls1981: Object, miranda2025singlehtml: Object, shank2025hostile: Object, klokmose2015webstrates: Object, litt2025malleable: Object, beck2019hourglass: Object, smith1984reflection: Object, maes1987reflection: Object, kiczales1991amop: Object, ingalls1997squeak: Object, tc39tostring: Object, horowitz2023lrc: Object, foster2007lenses: Object, fabricyarn: Object, sm64decomp: Object, backstitch2026: Object, …}
edit
edit
externalLink = ƒ(…)
edit
aside = ƒ(title, module_names)
edit
experiment = ƒ(content)
edit
sections = Array(16) [Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object]
edit
sectionIndex = Map(16) {"ship" => Object, "claim" => Object, "cell" => Object, "modular" => Object, "copy" => Object, "mappings" => Object, "html" => Object, "atproto" => Object, "iife" => Object, "liberation" => Object, "jam" => Object, "agent" => Object, "waist" => Object, "related" => Object, "limits" => Object, "questions" => Object}
edit
sec = ƒ(key)
edit
ref = ƒ(key)
edit
edit
viewof essayModule = EventTarget {tag: Symbol()}
edit
edit
edit
edit
edit