ARCHITECTURE · EXEC TIERS
Running a binary that lives inside an image.
An interpreted application never execs anything — the interpreter runs inside the mounts. But a toolkit payload ships real executables, and an exec target held by a virtual filesystem needs a path to the CPU. Tebako has four, and the payload's manifest declares which one it takes — consumers never care which path a tool took.
Choosing a tier, as a flow.
The payload publisher makes this choice once; the dispatcher honors it silently. The questions, in order:
dynamic — the preload shim
SHIPPEDA small interposition library is injected into the process at launch and maps the standard file-IO calls onto the mounted images. The binary — and every library it dynamically loads — sees the images as ordinary directories. Nothing is extracted; jails apply, because the IO flows through the same policy choke point.
Choose it when: The mainline. Any dynamically linked executable: Inkscape, a JVM, ffmpeg, git.
Honest limits: Dynamic binaries only. A raw-syscall caller bypasses interposition; macOS system binaries strip the injection variables.
tfs-native — built against the VFS
SHIPPEDThe binary is compiled against the tebako filesystem interface and carries the VFS inside itself. The patched ruby interpreter is the canonical example: it mounts and serves its own stdlib from the env image, no shim involved.
Choose it when: When you build the tool yourself and can link the interface. A build-time property — it cannot be imposed on an arbitrary binary.
Honest limits: Requires source access and the tebako SDK.
static — extract the closure
SHIPPEDFor statically linked tools, interposition has nothing to attach to. The executable and its declared closure are materialized once into a content-addressed exec cache in the store — verified at install — and run from there. On macOS and Windows this is also the fallback for anything the shim cannot mediate.
Choose it when: Statically linked binaries; platforms without a syscall-mediation surface.
Honest limits: Such processes see only the host filesystem — no VFS, and jails do not reach them. That is a platform-API statement, not a trust statement.
wrapped — link-time interposition
PLANNEDThe same interposition as the dynamic tier, bound at link time instead of launch time — for binaries you build but cannot make fully TFS-native.
Choose it when: Named in the manifest vocabulary today; the mechanics ship in a later milestone.
Honest limits: Not yet specified.
The hardest case: an image execs an image.
The metanorma proof runs exactly this: a ruby process, inside its mounts, shells out to a JVM and to Inkscape — both of which live inside disk images. Three mechanisms make it work. The runtime mediates process spawning: an exec target held by the mounts is materialized to a host cache and executed there. Before exec, the loader walks the binary's dependency closure — rpaths, @executable_path, $ORIGIN — and materializes every in-image library it needs, because the platform loader probes for shared libraries with raw syscalls no userland hook can serve. And the spawned child re-enters the namespace through the preload shim with the mount table injected into its environment, so the grandchild of a packaged app sees the same virtual filesystem as its parent.
The result is unglamorous and important: PATH= metanorma compile site.adoc produces a PDF. Nothing on the host participated, so nothing on the host can break it.