Skip to content

Recipe File

onelf.toml is a declarative recipe that replaces long CLI invocations. One file captures everything needed to reproduce a pack.

Minimal recipe

toml
[package]
name = "myapp"
command = "bin/myapp"

Drop this next to the AppDir and run:

bash
onelf build

Full example

toml
[package]
name = "amdgpu_top"
command = "bin/amdgpu_top"
output = "amdgpu_top.onelf"
version = "0.11.3"
description = "Tool to display AMDGPU usage"
license = "MIT"
homepage = "https://github.com/Umio-Yasuno/amdgpu_top"
working-dir = "package"

[[entrypoint]]
name = "amdgpu_top-smi"
path = "bin/amdgpu_top"
args = ["--smi"]

[[entrypoint]]
name = "amdgpu_top-gui"
path = "bin/amdgpu_top"
args = ["--gui"]

[compression]
level = 12
dict = false

[update]
url = "https://releases.example.com/amdgpu_top.onelf.zsync"

[bundle]
search-paths = ["${MUSL_LIBDRM}", "${MUSL_GCC}"]
strict-libc = true
scan-dlopen = true
dlopen = ["libmyvendor.so.1"]

Sections

[package]

The main entry. Covers the default entrypoint's command, output file, runtime behavior, and metadata.

FieldTypeDefaultDescription
namestringderived from commandPackage name
commandstringrequiredPath to main binary, relative to AppDir
outputpath{name}.onelfWhere to write the packed file
working-direnuminheritinherit, package, or command
memfdboolautoForce memfd-eligible (auto-detected otherwise)
excludearray[]Glob patterns to exclude from the pack
versionstringnoneShown by onelf info
descriptionstringnoneShown by onelf info
licensestringnoneShown by onelf info
homepagestringnoneShown by onelf info

[[entrypoint]]

Additional named entrypoints. Each one becomes accessible via argv[0] matching: symlink the packed binary to that name and it runs the matching entrypoint automatically.

FieldTypeDefaultDescription
namestringrequiredEntrypoint name (argv[0] match)
pathstringrequiredPath to binary within AppDir
argsarray[]Args always prepended to the invocation
defaultboolfalseRun this one by default

[compression]

FieldTypeDefaultDescription
levelint12Zstd level, 0 to 22
dictboolfalseTrain a shared dictionary for better ratio
storeboolfalseStore payload raw, no zstd (overrides dict/level)

[update]

FieldTypeDefaultDescription
urlstringnonezsync control file URL

Setting [update] automatically selects the update-capable runtime (~2 MB larger than the default slim runtime).

[bundle]

Everything bundle-libs accepts, as recipe keys.

FieldTypeDefaultDescription
lib-dirsarray["auto"]Bundled directories the runtime adds to its lib search (pass ["auto"] to detect)
search-pathsarray[]Extra lib search paths (highest priority)
excludearray[]Excluded soname prefixes
includearray[]Force-included sonames
gl / dri / vulkan / wayland / gtkboolautoFramework bundlers
stripboolfalseRun strip on bundled libs
strict-libcboolfalseRefuse wrong-family libc libs
scan-dlopenboolfalseScan for dlopen'd libs in binary strings
dlopenarray[]Extra sonames for scan-dlopen allow-list
skipboolfalseDon't run bundle-libs at all

[env]

Custom environment variables set by the runtime before exec.

toml
[env]
PYTHONHOME = "${ONELF_DIR}/python"
QT_PLUGIN_PATH = "${ONELF_DIR}/lib/qt6/plugins"
GST_PLUGIN_PATH_1_0 = "${ONELF_DIR}/lib/gstreamer-1.0"

${ONELF_DIR} expands to the package root at runtime (the FUSE mount, tmpfs, or cache dir depending on execution mode), so values follow the running app wherever it lives. Other ${VAR} references expand at recipe-load time against the packer's environment.

To defer a reference to runtime instead, escape the $ with $$: $${VAR} reaches the package as ${VAR} and is expanded against the live process environment when the app runs. POSIX ${VAR:-word} is supported: if VAR is unset or empty, the literal word is used instead. This is how you prepend rather than replace:

toml
[env]
PATH = "${ONELF_DIR}/bin:$${PATH}"   # bin/ first, keep the caller's PATH

$ONELF_DIR/bin is added to PATH by default. Every package behaves as if it had:

toml
[env]
PATH = "${ONELF_DIR}/bin:$${PATH:-/usr/bin:/bin}"

so bundled helpers resolve even when the app or a sandbox clears PATH. (glibc's _CS_PATH fallback — /bin:/usr/bin — only applies when PATH is unset; the moment onelf sets PATH it no longer kicks in, so the :-/usr/bin:/bin default substitutes it explicitly when the inherited PATH is empty, instead of leaving a dangling empty element.) Set [env] PATH yourself to take full control (the default is then skipped); use PATH = "$${PATH}" to opt out of the bin/ prefix entirely.

These variables are re-exec-safe: a small onelf-env constructor is bundled into lib/ and injected as a DT_NEEDED of the entrypoint, so .onelf/env is re-applied on every exec — including after an app re-execs itself in a sandbox that calls clearenv() (Chromium/Electron zygotes, Steam, bwrap, etc.). This requires patchelf at pack time; without it the values are only set for the first launch. See Environment › Surviving a sandboxed re-exec.

preload

A top-level list of libraries to dlopen on every exec, via the same onelf-env constructor. Unlike LD_PRELOAD (an env var, wiped by a sandboxed re-exec), this is baked into the ELF and survives.

toml
preload = ["${ONELF_DIR}/lib/libfoo.so", "libbar.so"]

${ONELF_DIR} expands at runtime. CLI equivalent: --preload PATH (repeatable).

Environment variable expansion

Any string in [bundle] search-paths (and other path fields) expands ${VAR} references at parse time:

toml
[bundle]
search-paths = ["${MUSL_LIBDRM}/lib", "${HOME}/my-libs"]

Missing variables expand to empty strings.

Path resolution

Relative paths in the recipe resolve against the recipe's directory, not the caller's cwd. This means running onelf build from anywhere always produces the same result.

bash
onelf build             # looks for ./onelf.toml
onelf build path/to/app # looks for path/to/app/onelf.toml
onelf build app/recipe.toml  # any .toml file works

Overriding at the CLI

A few flags override recipe values:

bash
onelf build -o custom-output.onelf    # overrides [package] output

For anything more specific, edit the recipe directly.

Released under the MIT License.