Skip to content

Runtime modules & guest agents

Two extension points that most contributions touch: teaching autopsy to understand a new kind of file, and giving rvmc a guest agent for another operating system.

Autopsy: teaching it a new runtime is a data edit

The primary extension path writes no code at all. Runtime detection is data-driven: a single dispatcher walks runtime/runtime-catalog.yaml, where each entry is a self-contained runtime module — detection signals (extension / magic bytes / container structure / embedded strings), the analysis plan, the ordered environment recipe, fidelity notes, and the runtime’s known endpoints. Teaching autopsy a new runtime means adding one catalog entry; the dispatcher loads every module whose matches fires (multi-runtime is normal), and unmatched formats fall through to the AI fallback module rather than a forced wrong guess.

Write a new extractor only when a new format tool is actually needed — a parser for a container no existing tool reads. For that case, the doctrine below applies.

Autopsy: per-kind extractors

Autopsy handles each kind of code with its own module, and every module obeys the same doctrine:

A module EXTRACTS generic signals. It never JUDGES, never validates, never fits one artwork.

That is the load-bearing rule. A module surfaces facts (formats, strings, references, network-protocol indicators) fairly and hands them up; the analyst reconstructs and decides. Concretely:

  • No validation / no scheme-matching. Don’t “clean” or regex-filter URLs — a work may construct a URL over several steps, and a scheme filter would drop it. Surface the protocol indicator and let the analyst read the code.
  • No set-fitting. A rule that happens to be true for one artwork (drop this extension, prefer that file) must not be hardcoded — build something that can’t starve one source in favor of another (fair, round-robin allocation; normalized dedup).
  • No starvation. Every source gets a fair share of attention even in a huge tree; if you must cap, log what was dropped — never silent truncation.

Practical shape of a new extractor:

  1. It registers itself (side-effect import) and runs over the unpacked members it recognizes.
  2. It emits findings (kind/layer/summary/evidence) — generic signals, deduped.
  3. If it can go deeper on demand, it exposes a deep-read the analyst can call as a tool.
  4. Reuse the shared network probe rather than writing a parallel URL extractor.

Existing modules (Director/Lingo, PE/ELF, installers, media, etc.) are the templates. Add tests that assert extraction, not classification — the AI does classification, so don’t bake a verdict into a deterministic test.

Installers are not automatically “not art”

An installer can be the artwork (a self-installing or packed work). Detection feeds preflight, which asks; a module must not decide an installer is runtime bloat and drop it.

Scoping: artwork vs. bundled runtime (distinct from preflight)

Preflight is a whole-bundle question asked once, up front. Scope — which subtree is the work and which is the runtime it merely carries — is settled in three steps, in order:

  1. The orient judge, first. Right after preflight, a deterministic bundle portrait (the tree + per-executable metadata) is put in front of an LLM judge that names the entry point(s) and the work-vs-commodity partition — before anything is collapsed. The judged entry fills in at LLM-fallback authority only; a deterministic or human entry always wins.
  2. The anchor-aware collapse. The deterministic detector recognises the unambiguous vendored runtimes from structural signals alone (a JRE/JDK tree, a node_modules, a Python site-packages, a Processing or .NET runtime) and collapses each to a single opaque nodein the analysis graph only; nothing is deleted, the runtime still ships into the VM. The collapse keeps the artwork’s own anchors — the entry point and the orient-judged work members — visible through the collapsed tree (a Unity build’s launcher and Assembly-CSharp.dll survive while the engine’s Build/ tree becomes one node).
  3. The in-graph scoping specialist, for the hard cases. A sub-agent judges the genuinely ambiguous subtrees across ecosystems (JVM / Processing, .NET, JS, Python), and prefers to keep when unsure — excluding the artwork is worse than graphing a few extra dependency files.

A new extractor must respect this: don’t drop or hide files a scoping decision owns. Surface them; the orient judge, the collapse, and the specialist decide what is opaque runtime and what is the work.

rvmc: guest agents

Every golden image ships a guest agent — an in-VM helper the controller talks to, so it can act inside the guest (run commands, read/write files, send keys, screenshot, read the event log). A golden without a working, reachable agent is not a usable golden.

Contributing a guest agent for an OS:

  • Match the era. Old guests need era-appropriate runtimes (e.g. an older Python, or a native helper) — don’t assume a modern toolchain is available in the guest.
  • Provide the same capability surface the controller expects, so per-OS quirks stay behind the agent (cursor/mouse handling, event-log access, networking transport).
  • Networking into old guests is often the hard part (NIC driver availability); document the working NIC and transport for the tier.

The per-OS agent builds live alongside the controller; use an existing tier (e.g. the Windows agents) as the template and follow its capability contract.

Testing

  • Autopsy: deterministic tests over real fixtures; assert extracted signals. LLM-touching paths must degrade to a trace line and never crash the pipeline.
  • rvmc: exercise the controller/bridge against fakes; guest-agent changes want an actual boot on the target tier before calling them done.