myapp/
├── bin/
│ └── myapp # the entry script
└── lib/
└── myapp.rb
GUIDES · 04
Package a Ruby app.
tebako press turns a source tree into one executable per platform. You compile only your own code — the runtime and the loader arrive as prebuilt binaries.
|
Note
|
This guide pairs with parts 3 and 4 of the Basic payloads tutorial, which package a single Ruby app and then a Rails app. |
Decide: lean or fat.
Lean — the default. The package is bootstrap + your payload + a trailer. The first run on a machine downloads the shared runtime once; every package that accepts the same ruby line reuses it. Smaller file, one runtime per machine. Choose lean whenever the machine has a network path at first run.
Fat — -m fat. The runtime travels inside the package as a slot,
pinned by SHA-256. Bigger file, zero network at run time, nothing
shared. Choose fat for air-gapped machines, USB hand-offs, and
strict-offline environments.
The press command.
Given a tree with an entry script:
press it into an executable:
$ tebako press -r ./myapp -e bin/myapp -o myapp
-r is the source root, -e the entry script inside it, -o the
output file. -R picks the ruby version (default 3.3.7). -c pins the
working directory the app starts in; -p overrides the in-image prefix
the root is packed under — both rarely needed. -l error|warn|debug|trace
sets press’s own log level. --format dwarfs|limnifs picks the image
format the payload is written in — limnifs is the default; dwarfs
stays a first-class opt-in, and existing dwarfs images read everywhere
they always have.
The v1 modes are gone by design: -m classic and -m runtime fail with
a named error, and there is no tebafile — -t is rejected.
Extra slices, baked policies, standalone-only.
$ tebako press -r ./myapp -e bin/myapp -o myapp \
--image acme-fonts-2.1.0.tfs:/usr/share/fonts/acme \
--jail ./jail.yaml
-
--image <path>:<mount>packs an additional payload slice into the package and mounts it at the given path. Repeat it per slice — a fonts image, a dataset, a native toolkit. -
--jail <spec>bakes a filesystem policy into the package — a profile word or a YAML file. Users can tighten it at run time, never loosen it; see the jails guide. -
--no-installfreezes the package to standalone-only: it executes directly, andtebako installrefuses it with a named error (exit 76).
One package, several commands: suites.
A suite presses one package that carries several entry points; each becomes its own shim when installed. Describe it in YAML:
# suite.yaml
name: acme
version: 1.4.0
entries:
- name: acme
root: ./cli
entry: bin/acme
- name: acme-index
root: ./indexer
entry: bin/index
Press the suite:
$ tebako press --suite suite.yaml
An entry may pin its own runtime with a runtime_ref key; entries
without one share the suite’s resolved runtime.
What press resolves.
Two artifacts come from outside your tree: the ruby runtime (interpreter executable plus env image) from the runtime factory’s release index, and the bootstrap loader from the tebako releases. Both are downloaded and SHA-256 verified during press.
--prefer-local prefers artifacts already in the store over fetching.
--bootstrap <path> swaps in a specific loader binary (also settable as
TEBAKO_BOOTSTRAP). --tebako-version <v> pins the tebako toolchain
release press fetches its artifacts from. TEBAKO_RUNTIME_MIRROR
redirects runtime downloads to your own mirror (an https or file://
base URL) — the air-gapped partner of -m fat.
Test the result.
$ ./myapp --help
$ tebako inspect ./myapp
$ tebako inspect --contract ./myapp
inspect reads the package’s trailer and manifest: what it is, which
handoff contract it speaks, its trust state. The full surface is in
info & inspect.
A note on native extensions.
A payload with compiled gems pins the ruby ABI line it was built against
— ~> 3.3.0 — plus the platform ABI string. A machine whose cached
runtimes offer no compatible line fails at resolve time with a named
error, never a segfault. Pure-ruby payloads declare a range instead —
>= 3.3, < 5.0 — and one universal payload serves every platform.