<runtime> --tebako-image <self|image-path>:<slot|->:<mount> ...
[--tebako-trace <host-path>]
--tebako-entry <argv0> <user args...>
<self> the running executable's own package file; <slot> picks the
trailer-described region
<image-path> a standalone file — BARE (no trailer): slot 0 ≡ - ≡ whole file;
PACKAGED: numeric slot only, "-" is a named error
<mount> a POSIX absolute path on EVERY platform — on windows the driver
qualifies it onto the runtime root's drive (A:/t/…) before
mounting; a declared mount naming a drive is malformed
ARCHITECTURE · 11
The driver contract.
The driver is the code inside every runtime executable: it mounts the environment image and the payload slices, applies the jail, and rewrites argv to the entrypoint. This page is the wire that the driver speaks, language-agnostic by construction: ruby is the first runtime, and python or julia follow the same contract unchanged.
|
Note
|
The contract is shipped: the reference implementation is crates/tebako-driver (Rust, staticlib + rlib), and the v1 C++ tebako-main driver is retired. |
The invocation surface
One grammar serves every platform. Everything before the first --tebako-
is the loader’s, and everything after --tebako-entry is the user’s,
verbatim. An unknown --tebako- flag is a named error, never silently
ignored.
Mount order + failure rule
The env image mounts first (whole-file, from TEBAKO_RUNTIME_IMAGE), then
payload triples in argv order. The table is longest-prefix; nested mounts
are legal, and a duplicate exclusive mount point is EEXIST. Any failure
unmounts everything, never a partial mount. A runtime-role slot
(format_id = 4) is never mounted.
Mount modes
Every mount is exclusive (default) or union, declared per slot in the
package manifest’s mounts: block, never on the argv wire, so the launcher
ABI is unchanged and older drivers refuse a union package loudly. Union
conflicts resolve by declared precedence (after-env or after:<slot>),
and the union set is journaled at boot. Shim-dispatched payloads (no package
manifest) are always exclusive.
The entry, and the argv rewrite
--tebako-entry separates loader args from user args. The entry resolves
against the first --tebako-image mount (the app payload), or the
runtime root when no image spec is given, and the driver verifies its
presence against the mounts the boot itself established (named 65 when
absent). A bare NAME with no / (e.g. ruby) is the interpreter keyword:
the boot starts the interpreter itself and drops the keyword. With images
but no entry at all, the boot mounts and starts the interpreter with its
own args (the smoke form).
On success the process argv is replaced with
[<original argv0>, <entry resolved in the VFS>, <user args…>], the
program name stays at index 0, so the interpreter parses its argv
conventionally and takes the entry as its script. The jail installs after
the mounts; --tebako-trace arms the trace bus before any mount (a
channel that cannot be opened is a loud stderr note and a disarmed bus,
because observability never gates a boot).
The mount root is a default, not a constant
The runtime root is a per-platform baked default owned by the runtime
factory (ruby: /tfs on POSIX, A:/t on windows); it flows from the
source patches through the factory into the exe, and nothing downstream
re-authors it. TEBAKO_MOUNT_ROOT redirects the env-image mount at boot:
|
Note
|
The override, stated plainly. The value is validated before any mount: it
must be absolute, with no trailing slash and no |
The handoff environment
The loader speaks to the driver through a small, fixed set of variables.
Each one is a single-owner flow: declared by the factory or the manifest,
consumed verbatim, and never re-authored downstream. The exhaustive table of
every TEBAKO_* variable in the system lives in the reference section; the
contract’s own variables follow:
| VARIABLE | MEANING |
|---|---|
|
The absolute path of the runtime’s own env .tfs, mounted whole at the runtime root first, before any payload triple. |
|
The image:mount,… list; it is the mount table a spawned child re-establishes through the preload shim (the spawn-hook path). |
|
The jail policy in env form; it is enforced by the driver and installed after the mounts, and a malformed policy is exit 73. |
|
The trace bus channel (JSONL), armed at boot before any mount; the argument wins when both are set, and it is never policy-gated. |
|
Per co-mounted payload, its physical mount point (/tools/inkscape → TEBAKO_MOUNT_TOOLS_INKSCAPE); two mounts slugging alike is a named 65, and the root mount exports nothing. |
|
The boot rebuilds it: launcher wrap-bin dir → co-mounted dependency bin dirs (from each image’s own manifest, in triple order; the app payload never contributes) → windows alias dirs → the inherited PATH. A corrupt manifest or an unmaterializable declared executable is a named 65. |
The named exit codes
|
Note
|
The exit-code table is shipped, with no silent fallbacks. |
Loader-side failures keep the loader’s named codes, and runtime-side failures use the interpreter’s own codes. There is no catch-all, and no code does double duty; the shared constants live in crates/tpkg, and every emitter references them.
| CODE | NAME | RAISED WHEN | EMITTER |
|---|---|---|---|
65 |
|
The tpkg trailer or package manifest is corrupt or internally inconsistent; |
bootstrap · driver |
66 |
|
The package declares a launcher ABI this loader does not speak. |
bootstrap |
67 |
|
The runtime_ref is unparseable (type / version / constraint grammar). |
bootstrap |
68 |
|
An overlay/decrypt binding failed: an unbound retained store, missing or non-opening key material, an unwritable store, an orphan binding, or malformed |
resolver · driver mount path |
69 |
|
The runtime cannot be obtained: the download failed, or |
bootstrap |
70 |
|
A sha256 mismatch occurred on a downloaded artifact (exe, env image, dll) against the release index. |
bootstrap |
71 |
|
A signed package’s signature fails verification (strict, always). |
bootstrap |
72 |
|
The signer’s key is not in the trust store, or |
bootstrap · install path |
73 |
|
The jail policy is malformed or unusable; it is parsed and applied after the mounts, never before them. |
driver |
74 |
|
A host I/O failure occurred on the cache/install/lock paths. |
bootstrap · resolve |
75 |
|
The runtime is pre-era (it declares no contract set) or speaks a contract the loader refuses; the check fails closed before any install or execute. |
bootstrap |
76 |
|
A store install cannot complete (lock timeout, disagreeing digest anchors, or partial state that tmp+rename cannot hide). |
resolve · cli |
77 |
|
A package/payload contract-era mismatch in either direction, raised by any trailer or manifest reader. |
tpkg · pkg · cli |
78 |
|
The env-image layout mismatches: a mount_root override the image never granted, a missing preload-shim grant, or an interp ABI pair the image does not declare; it is also the preload shim’s |
driver · libtfs-preload |
79 |
|
A payload check FAILed, and the verdict line names the check and the failed expectation (SKIP never fails the aggregate). |
tebako check |
Two out-of-band codes complete the picture: the runtime factory uses 132
for a pre-era or corrupt source tarball, and --tebako-extract (the
runtime-side option, carried through the user-arg passthrough) dumps
mounted images to disk and exits 0. The trace subcommands carry their own
verdict codes (0 clean / 1 finding / 2 error); see
observability.
Negotiation is fail-closed
A runtime whose driver implements this widened grammar (image-path triples,
bare-file slot tokens, env-image-first multi-mount, and direct entry
execution) declares contract_version 2 in its release manifest, and the
compiled-in constant (tebako_driver_contract_version()) must agree with
the manifest. A runtime that declares no contract set is pre-era: the
loader refuses it by name with exit 75, before any install or execute.
Runtime provenance is declared in the payload manifest (provides, naming
engine, version, abi_line, and platform, plus built_from), and the
dispatcher’s compatibility check consumes exactly those fields.