Skip to content

Architecture

A map for contributors. Two services, each with a clean seam between deterministic machinery and the LLM layer.

artwork-autopsy

A pipeline that turns a bundle into a conservation report. Shape:

intake → static core (deterministic) → preflight → orient → scope collapse
→ run-graph build + deep-read (fixpoint) → ANALYST SESSION LOOP (agentic) → synthesis
  • Static core — the deterministic extractors in static/tools/ (self-registering, run over the unpacked members), with domain/ pure logic sequencing them: unpack, format-ID, hash, entry-point resolution, binary/import parsing, and the network-indicator sweep. No framework, no LLM. This layer extracts and never decides (no validation, no set-fitting, no starvation).
  • Preflight (step 1.5)domain/preflight.py: detects a possible bundled runtime installer and asks the researcher (never rejects). On the async path this is a two-phase pause: the pipeline returns early at an awaiting-confirmation status, and a confirm resumes it over the already- unpacked workspace.
  • Orientdomain/phases/orient.py, run after preflight and before the scope collapse: a deterministic bundle portrait is judged by the LLM for the entry point + the work-vs-commodity partition, so the collapse below can keep the artwork’s anchors instead of subtracting them blind. The judged entry fills in at LLM-fallback authority only — a deterministic or human entry always wins.
  • Scope collapse — opaque vendored-runtime subtrees collapse to single nodes, anchor-aware: the entry point and the orient-judged work members stay visible through the collapsed tree.
  • Run graph + deep-read — builds a graph of the work (entry point, imports, references, containment) and deep-reads every important unread node, relooping to a fixpoint until the read-list is drained and the KB stops changing (no top-N coverage gate; only a defensive runaway backstop).
  • Analyst session loopai/investigate/: a tool-using pydantic-ai agent with navigation (list/grep/read-slice), graph, and extraction tools. It runs with no caps; the bound is agent-complete OR researcher cancel (a cooperative flag → graceful partial). Its findings merge into the KB, which rides into the next session so it extends rather than restarts.
  • Synthesis — projects the accumulated KB into the layered manifest, behavior map, runbook, and suggestions.

The post-preflight sequence is not a hand-wired call chain: it is a declared phase plan (domain/orchestration/) whose read/write dependencies are validated before it runs, so a reorder that breaks a data dependency fails at startup, not mid-analysis.

The seam rule: pydantic-ai is import-banned outside ai/ (enforced by a lint rule + a check script). The LLM lives behind adapters; the deterministic evidence stands even if the AI layer is degraded.

Jobs. Analysis runs as jobs on a PostgreSQL store (SELECT … FOR UPDATE SKIP LOCKED claim loop). A dumb runner supervises one child process per job (autopsy run-job), heart-beats, enforces a timeout, and reconciles the exit. Statuses: queued → running → done | done-partial | failed, plus awaiting-confirmation (the preflight pause) and staging (drive-path bundle staging).

rvmc (research-vm-controller)

The workbench: clone era-correct VMs, drive the guest, capture the network, save state.

  • Controller — libvirt/KVM lifecycle: clone a golden into a project, boot/power, snapshot.
  • Golden catalog — the era-correct base images; each ships a guest agent.
  • Guest agent — a per-OS in-VM helper (Windows 2000 … 10 and Mac OS 9.2.2 today; 11, 98 SE and Mac OS X Tiger in progress) exposing run-command, file I/O, keys, screenshots, event log — the controller’s hands inside the guest.
  • Drive lifecycle — one project = one artwork; a durable drive carries the stage (analysis → workbench → …) and the deliverables, independent of the services.
  • Analysis bridgervmc/analysis.py: dispatches autopsy on the project’s drive, reads the report back, surfaces the preflight pause, and confirms/cancels it.
  • Agent surface (MCP)rvmc/mcp_tools.py: the workbench capabilities as tools for an LLM agent (see MCP tools), exposed via Open WebUI, scoped per project.

The pipeline: autopsy → rvmc → evmc

The core idea — three stages, one artwork moving left to right. Each stage has exactly one job; the boundary between them is a durable handoff, not a live coupling. Get the stage boundaries wrong and everything downstream rots — so this is the canonical statement.

The whole platform is one method, first reported in the paper that grew out of the Choose Your Filter! exhibition [1]: do the research for as long as it takes to get the artwork into the three-layer model, then bake Layer 1 into a verified snapshot and never touch it again. The three stages below are just that method made operational — autopsy and rvmc are the “for as long as it takes” research; the handoff to evmc is the bake-and-freeze. The three-layer model is the target the research aims at; the snapshot is what makes Layer 1 permanent.

  1. autopsy — understand the artwork. Turn the bundle into a conservation report: what it is, what it depends on, how to bring it up. Deterministic extraction + an agentic analyst. No VM, no repair.

  2. rvmc — restore, and build the conservation unit. Bring the work back to life and build everything it needs to run unattended for months: the era-correct VM, the fixes/shims/mirrors, the auto-heal + self-repair infrastructure, the conservation plugin(s), the guest monitoring. rvmc proves the work runs and defines what “healthy” means. This is where the AI + human are; it is expensive and one-time-per-artwork. rvmc does not bake the final image and does not stamp the exhibition snapshot.

  3. handoff → evmc — bake, prove, snapshot, ship. The handoff turns rvmc’s proven project into a field-ready conservation unit, strictly in this order:

    1. bake the image — flatten the overlay chain onto its base into one standalone disk;
    2. boot it on/toward the dedicated machine and let it warm up to its verified-good state;
    3. only once it proves to run (healthy / verified live) stamp the ready snapshot — a live memory + disk snapshot, so a revert resumes the exact warmed state in 3–5 s with no boot (the iPRES paper’s guarantee);
    4. hand the finished unit to the dedicated exhibition machine, where evmc is just the player: on any fault it reverts to ready, forever, deterministically, with no AI.

The ready-snapshot timing rule — do not mess this up

The ready snapshot is NOT made in rvmc and NOT baked into the bundle. It captures memory + disk — the paper’s guarantee is that a revert “resumes execution at the snapshot point without boot sequences” in three to five seconds [1] — so it can only be taken while the VM is running and warmed to the verified-good moment, which is at the handoff, after the baked image proves it runs on the target. Baking (qemu-img convert) flattens disk only and drops internal snapshots; an import-time, VM-shut-off snapshot is disk-only (a cold baseline, not the real ready). The live ready is stamped at the last point where the running state exists on the machine that will play it. evmc-the-player only ever reverts to ready; it never creates it. The bundle carries the ready state (the disk) and the ready name; the handoff materialises the ready snapshot.

This maps onto the paper’s three-layer runtime model [1]: Layer 1 — the VM guest (OS, browser, plugins, artwork), “never modified after initial setup” — is the conservation object rvmc authors and the handoff freezes as the snapshot; Layer 2 — the host controller + the Wayback Cache Proxy — is the preservation infrastructure evmc plays; Layer 3 is the managed external dependencies, isolated in replaceable host services so preserving a work never means freezing the live internet. The paper’s finding is the whole reason for the stage split: every error inside the encapsulated environment was recovered automatically; every failure outside it required a human — so Layer 1 is baked and inviolable, and all the fragility is pushed out to Layer 2/3 where it can be serviced without touching the conservation object.

How they connect

rvmc dispatches an autopsy job for a project’s artwork (POST /jobs/drive), polls status (including the preflight pause), and reads the deliverables off the shared drive. The report’s suggested base VM pre-fills the golden picker. The hand-off onward to the exhibition controller (evmc) is a promotion bundle — golden/baked image + boot config (snapshot name + plugins) + the conservation plugin + provenance, checksum-signed — which evmctl import unpacks on the field host; the live ready snapshot is stamped there per the rule above, then evmc plays it.

Contributor entry points

References

The pipeline and the three-layer model come directly from the Choose Your Filter! exhibition (ZKM, 2025) and its reported practice:

  1. M. Schütze, “Keeping Net Art Alive: Self-Healing VMs and a Caching Wayback Proxy from Six Months of Exhibition Operation,” iPRES 2026 (in press). — Introduces the three-layer model (conservation object / preservation infrastructure / managed external dependencies), the memory+disk “ready” snapshot with 3–5 s revert, and the self-healing boundary between internal errors (recovered automatically) and external failures (isolated to the host layer).

The tools this platform builds on are released under the MIT license: