A harness is only as good as its plugin system. An agent is only as good as its harness. Which makes unloading a plugin a more interesting problem than it sounds.
An agent is a model plus a harness — the thing owning its tools, permissions, session state, memory, subagents. Swap the harness and the same weights become a different product.
A harness is a plugin system wearing a hat. Tools arrive and depart, capabilities get added mid-session, and a self-improving one edits its own components while serving requests. That is dynamic composition, which our industry has never done well and works around by restarting the process.
A Programming Paradigm for Spatiotemporal Composability — Shi, Zhang and Cui, Peking University and DeepSeek-AI — spends eighty-eight pages making that precise.
Two dimensions. Temporal: removing a component completely reverses every modification it made. Spatial: components declare and resolve dependencies on each other in a checkable way. Statically both are boring — scoping and import resolution. Dynamically, both are unsolved, so the authors lift effects into revertible effects, where every context transformation carries an inverse the runtime tracks, and coeffects into reactive coeffects, where context changes notify components against what they declared.
The receipts land it. Among VSCode’s top 100 extensions, 87 contain executable code and cannot be removed without restarting the whole extension host. Only 7 declare a dependency on a non-built-in extension. On the deactivate hook: it separates effect disposal from effect creation, which “violates locality of concern and makes complete cleanup difficult to verify.”
That is every uninstall path I have written, described more honestly than I would have described it.
It ships, too. The implementation is Cordis; Koishi has four years and 4000+ community plugins riding on it. And Cordis’s documentation now lives under the DeepSeek Harness — so the composition layer this paper formalises sits underneath a shipping agent harness. The chain at the top isn’t rhetoric, it’s someone’s dependency graph.
We have built plugin systems. Unload was always a courtesy: a dispose callback, a decent attempt at unregistering listeners, a line in the docs saying restart to fully disable. I thought that was pragmatism. It was that I had never sat with the problem long enough to see it had a shape.
Next, we want to put the implementations side by side — VSCode, OSGi, Eclipse, OTP hot code loading, Emacs, browser extensions, Cordis — against fixed questions. Can a component be removed without restarting its host? Are effects tracked, or is cleanup a convention? Is the dependency contract checked? Before this paper that would have been a feature table. Now it can be an argument. We intend to hold our own harness to it.
Read sections 1.1 and 1.2. Five pages.