ADR-0005: lemonfiber embeds the stack at build time
Rendered from spec at76d46f3 (2026-10-25) · its source · Edit this page
Status: Accepted Date: 2026-07-24
Amended by ADR-0042: what is embedded is the bundle and the manifests it pins.
Amended by ADR-0043: what is materialised is the manifests, and the Compose project is generated from them.
Amended by ADR-0045: what is embedded is the bundle and each pinned plugin’s tree, and the build validates the bundle rather than stack.toml.
Context
Given ADR-0004, lemonfiber and lemonfiber-media-stack
are separate repos — so lemonfiber needs the stack’s files (compose.yml,
stack.toml, service configs, overlays) at runtime. How it obtains them
determines the first-run experience and the failure modes.
The first-run experience is the whole product thesis. Any step that can fail before the user has anything working is disproportionately expensive.
Decision
The stack is a git submodule, embedded into the binary at compile time via
include_dir!, and materialised to disk on first run.
lemonfiber/
├── assets/media-stack/ # git submodule, pinned to a tag
├── build.rs # validates schema_version at COMPILE TIME
└── src/stack/embedded.rs # include_dir!("assets/media-stack")
On lemonfiber init, files are written to the platform config directory
(~/.config/lemonfiber/stack on Linux, ~/Library/Application Support/… on
macOS, %APPDATA%\… on Windows). A --stack-dir <path> flag overrides this
entirely, pointing at a local checkout for development or customisation.
build.rs parses the submodule’s stack.toml and fails the build if its
schema_version isn’t one this lemonfiber supports.
Alternatives considered
| Option | Why it lost |
|---|---|
Fetch a release tarball on init |
Requires network at the worst possible moment — first run, before the user has any success. Adds TLS/proxy/rate-limit failure modes, and makes version skew a runtime error. |
git clone on init |
All of the above, plus requires git installed. Many Windows users don’t have it. |
| Ship stack files alongside the binary (tarball/installer) | Breaks the single-file distribution promise, and brew/scoop/curl | sh all become more complex. |
| Read from a user-specified path only | Zero-config first run becomes impossible; the user must obtain the stack themselves first. |
Consequences
Positive
- First run needs no network and no git. Download one binary, run it, get a working stack. This is the single biggest contributor to the setup-time goal.
- Version skew becomes a compile error.
build.rsvalidates the contract at build time, so an incompatible pairing can never reach a user. This is the strongest available mitigation for ADR-0004’s main downside. - Reproducible: a given lemonfiber version always materialises byte-identical stack files, making bug reports meaningful.
--stack-dirpreserves full hackability — a power user can fork lemonfiber-media-stack, point lemonfiber at it, and never rebuild.
Negative
- A stack fix requires a lemonfiber release. The main cost. Accepted because stack
changes are infrequent (a pinned image bump, a new service) and
--stack-dirlets urgent cases be worked around immediately. - Binary grows by the size of the stack files — a few hundred KB of text. Negligible.
- Contributors must remember
git submodule update --init. Mitigated by abuild.rscheck that emits a clear error ifassets/media-stackis empty, rather than a confusinginclude_dir!failure.
Neutral
- Materialised files are user-editable. lemonfiber detects local modifications (by
hash) and will not silently overwrite them on upgrade — it warns and offers a
diff (
FR-032).
Revisit if
- Stack changes become frequent enough that release coupling is painful.
- Third-party stacks become a real use case, favouring a fetch-based plugin model.