ARCHITECTURE · 02
What is tebako?
Tebako is a packaging and loading ecosystem rather than a Ruby tool. It stitches a payload into a single transparent executable that end users run without thinking about its mechanics, or it ships the payload as a managed, versioned, and signed package with shared runtimes. Ruby is the first runtime instance, and the loader neither knows nor cares which language it starts. Beneath this surface sits TFS, a userland virtual filesystem that allows ordinary binaries to mount disk images in-process.
|
Note
|
Standalone press is shipped: the lean and fat executables are released and downloadable today. Managed mode is shipped: the shims, per-invocation dispatch, and the shared cache are released. OpenPGP verification in the loader is planned in part and follows the unverified-first rollout; see the chain of trust for details. |
One design, generic across four axes
The platform is a single design, and that design is generic across four axes. Nothing in the loader, the container, or the store is shaped around Ruby; Ruby happens to be the first runtime that the factories produce.
- Any runtime
-
A runtime is a payload that provides an interpreter: ruby today, and python, julia, or any other language later. The loader hands off to an entrypoint, and it never learns a language.
- Any platform
-
Artifacts are built per platform triplet; eight triplets are locked, from
aarch64-macostoaarch64-windows-ucrt. The eighth triplet joined the axis at tebako v2.8.13 with the windows-arm64 authoring tools and the link unit, and the arm64 runtimes follow as the factories publish their legs; the other seven triplets carry the full tool set and the full runtime catalog. Pure-language payloads may also beuniversal. - Any payload
-
Application code, data, fonts, native tools, and runtimes themselves are all
.tfsimages of the same kind, and they differ only in what their manifests declare. - Any composition
-
Payloads stitch onto a single binary, and payloads recursively mount other payloads at paths. Composition is a manifest declaration, not a rebuild.
The six capabilities
Everything tebako does decomposes into six verbs.
| Capability | What it does |
|---|---|
Stitch |
The stitch operation combines N payload images and the bootstrap into one executable (fat), or it produces a small executable that resolves the parts on demand (lean). |
Load |
The loader mounts payloads, recursively, into one VFS and then transfers control to the declared entrypoint. |
Share |
Runtimes and payloads download once into a machine-wide content cache, and every package on the machine reuses them. |
Shim |
Every executable an installed payload provides becomes a registered command on PATH, dispatched per invocation. |
Jail |
The jail applies a declarative host-filesystem policy per run, and the VFS layer enforces the policy rather than the payload’s good behavior. |
Trust |
Signing and encryption are opt-in per package. Unsigned packages remain first-class: a signed package is verified strictly, and nothing is ever silently downgraded. |
A map of the platform
Everything in the platform orbits one seam: the tebako_fs_* C ABI, implemented by the Rust tfs crate. The factories feed runtimes to this seam, and feedstock repositories, one per package, build payloads on those runtimes and host them on their own releases; the factories walk that chain. The trust layer sits beneath everything that moves bytes.
Figure 1 — Platform map: the TFS core, the factories and the product line around it, the trust layer beneath.
The gem-era orchestrator is retired: the C++/gem codebase is archived at tamatebako/tebako-v1 and the product is the Rust workspace at tamatebako/tebako.
The three parts of every package
A tebako package is a composition of up to three independently distributable
parts, glued by the tpkg trailer: a 166-byte header at end of file plus
280-byte slot records. The format version is 1 forever: extensions live in
flags (LEAN, SIGNED_V2, NO_INSTALL) rather than in version bumps, so
v1 readers parse v2 packages untouched. The full byte tables live in
concepts.
Figure 2 — Anatomy of a tebako package: bootstrap, optional runtime slot (fat packages), one to eight payload slots, optional v2 signature extension, and the tpkg trailer header at end of file.
A · the bootstrap — the Rust loader, a static binary under 3 MB. It is the process entry point of every stitched package: it reads its own trailer, resolves the runtime, verifies it, and hands off.
B · the runtime — two artifacts rather than one: the interpreter
executable and the env image (a .tfs carrying the runtime’s files). They
are downloaded once into the shared cache, sha256-verified, and
mounted — never extracted. Fat
packages carry the runtime as a slot; lean packages carry a reference and
fetch on first run.
C · the payload slices — bare .tfs images, self-describing through an
in-image manifest (/tpkg/manifest.yaml). The container’s format_id
answers exactly one question, how to read the bytes (limnifs, dwarfs-t,
squashfs, zip); whether a slot is a runtime, and which payload carries the
entrypoint, are manifest semantics that are never encoded in the format
axis. LimniFS is the default image format as of tebako v0.2.0, and dwarfs-t
remains a first-class read backend.
The two execution modes
The engine is the same, and the two modes differ in the relationship between the developer and the user: the developer hands over one file and disappears, or the developer publishes versioned payloads that a dispatcher assembles per invocation.
Figure 3 — Standalone mode versus managed mode, side by side.
1 · The standalone mode
|
Note
|
This capability is shipped. |
A developer presses the application once per platform with the tebako CLI, a single static binary that requires no host Ruby, and publishes plain executables. The users of those executables download one file and run it: no Ruby, no gem environment, no tebako installation, and nothing else to know. The lean variant keeps the download small: the first run fetches the shared runtime once into the machine-wide cache, where every tebako package on the machine reuses it. The fat variant carries the runtime inside and never touches the network.
Figure 4 — Lean versus fat package flows: lean resolves the runtime from the shared cache on first run; fat embeds the runtime and never touches the network.
TEBAKO_OFFLINE=1 forces cache-only mode: the result is a cache hit or the
named error EX_TEBAKO_UNAVAILABLE (exit 69), never a surprise download.
2 · The managed mode
|
Note
|
This capability is shipped. |
A developer publishes signed .tfs payloads to the developer’s own GitHub
releases; the registry is a tpkg-registry.yaml manifest on infrastructure
the developer already has, and there is no central service and no default
registry. A user with tebako installed puts ~/.tebako/shims on PATH once
and then runs metanorma directly: the dispatcher picks the payload version
and a compatible cached runtime, with no download and no per-shell hook.
Payloads are immutable, and swapping rubies under a running tool is a
dispatch choice rather than a reinstall. Native-extension payloads lock to
the ABI line they were built against, and an incompatible line produces a
named compatibility error instead of a segfault.
mnenv retires in favor of the
dispatcher, and metanorma is the first consumer of the mechanism. The
dispatch page describes that mechanism.
Figure 5 — Version resolution: the payload version chain, then a compatible runtime from the cache.
TFS, the engine underneath
TFS is a product in its own right: a userland virtual filesystem with a
mount table, longest-prefix dispatch, pluggable read-only backends, and
copy-on-write and encryption transforms above them. The
Rust tfs crate
is the shipping implementation of the tebako_fs_* C ABI (33 exports),
and it drives every mount on this page. The C++
libtfs survives as the legacy
parity oracle, and the Rust ABI runs its contract suite byte-for-byte.
Figure 6 — The TFS router: longest-prefix dispatch onto read-only backends, with a copy-on-write overlay above and pass-through to the host outside every mount.
Any project, in any language, can attach images to its binaries through the same ABI, or it can drive images from the shell with the tfs CLI. dwarfs-t, the only C++ in the ecosystem, and dwarfs-t-rs, its standalone Rust binding, are consumable without any knowledge of tebako. Every backend is read-only at runtime forever; writing exists only as the copy-on-write overlay plus a creation-time writer. The the VFS model page presents the full model.
The trust chain
One signature mechanism, OpenPGP via rnp-rs, runs from the publisher’s key to the user’s run. Signing is opt-in per package, and verification of anything signed is always strict. Verification happens at install and never per run; failures are named exits, never crashes. Details appear on the the chain of trust page.
Figure 7 — The tebako chain of trust: root key, release keys, per-artifact SHA256 digests, and the tpkg v2 signature verified at install.
|
Note
|
The rollout phase is stated plainly. The loader that ships today is built
without OpenPGP verification, which is the unverified-first rollout.
Signed packages run with a loud |
The four audiences
The audience rule is stated once: prebuilt artifacts flow downward, and compilation never flows outward. Only the people building tebako itself ever compile tebako.
- People running packages
-
People running packages need no compilation machinery, no libraries, and nothing to install: they download the package and run it. With a fat package, the run does not even need a network. With tebako installed, one shims directory on PATH places every managed tool a command away, with version pinning that requires no attention.
- Developers shipping data
-
Developers shipping data need no compilation machinery:
tfs mkimage, a manifest, and a release suffice. Fonts, datasets, and tool assets become content-addressed images, signed when the publisher wants signing, and mounted whole. - Developers shipping applications
-
Developers shipping applications compile only their own code. Tebako itself arrives as binaries, and the runtimes are prebuilt downloads. A developer presses once per platform in a matrix CI job, without special handling per target, and publishes to releases the developer already owns.
- People hacking on tebako
-
People hacking on tebako are the only audience that needs the tebako toolchain: the factories, the product workspace, and the contract suites. The entry points are the repo map and the contributor page.
The four audiences meet the platform matrix at different depths, and the windows-arm64 triplet is the one place where that depth differs per audience.
| Audience | On macOS and Linux | On Windows |
|---|---|---|
People running packages |
Stitched packages and the managed shim install run on every macOS and Linux triplet, x64 and arm64 alike. |
Every published package runs on windows x64 today. A windows-arm64 machine runs those same x64 artifacts under the emulation layer of Windows 11 today; native arm64 packages arrive with the arm64 bootstrap, shim, and factory runtimes. |
Developers shipping data |
|
|
Developers shipping applications |
|
The full authoring flow runs on windows x64 today. On windows-arm64, tebako v2.8.13 ships |
People hacking on tebako |
The product workspace and the contract suites build on every triplet that the continuous integration matrix covers. |
The product builds on windows x64 with the MSYS2 ucrt64 toolchain and on windows-arm64 with the MSYS2 clangarm64 toolchain, and the aarch64 link unit ships from tebako v2.8.13 as the input that the runtime factories consume. |
One toolchain note applies to Windows as a whole. The shipped binaries are compiled with GCC under MSYS2 ucrt64 on x64 and with clang and libc++ under MSYS2 clangarm64 on arm64, because MSYS2 publishes no GCC for aarch64 windows. An MSVC build of tebako is not shipped on either architecture; MSVC appears in the pipeline only as the host compiler for build-time helpers.
See also: concepts · the factories · the VFS model · runtime as image · dispatch · the store · the chain of trust · the repo map · for contributors.