← The specification

Vision

Rendered from spec at76d46f3 (2026-10-25) · its source · Edit this page

Status: Accepted


The problem

Self-hosted media automation works well once it’s running. Getting there is the problem, and it’s a problem with three distinct faces:

1. Setup is an afternoon of undocumented tribal knowledge. The canonical path is: find a Reddit compose file, paste it, fix the paths, discover your imports are copying instead of hardlinking, read the TRaSH guides, redo the paths, generate API keys by hand, wire six services together through six different settings UIs, and then never touch it again out of fear. None of that difficulty is essential — it’s the absence of a setup tool.

2. It’s all-or-nothing. Most stacks are a single compose file with a dozen services. Wanting to just search for an NZB means booting a media server, a request portal, a subtitle daemon, and four automation services. That’s not a resource problem so much as a conceptual one: the tooling has no vocabulary for “I only need part of this right now.”

3. Failures are silent and occasionally consequential. A VPN container that fails open still shows as Up. Imports that degrade from hardlink to copy still “work” — they just quietly consume double the disk and break seeding. A stack that reports green while doing the wrong thing is worse than one that crashes.

The product

A media stack you can run in slices, driven by a binary that sets itself up.

$ lemonfiber
  ┌─ lemonfiber ────────────────────────────────┐
  │  No configuration found.                    │
  │  Run first-time setup?              [Y/n]   │
  └─────────────────────────────────────────────┘

$ lemonfiber up search      # Prowlarr + NZBHydra2. Nothing else.
$ lemonfiber up tv          # + Sonarr, downloaders, subtitles
$ lemonfiber doctor         # prove the VPN isn't leaking

Three commitments:

Commitment What it means concretely
No proprietary components Every bundled service is self-hosted, and every one lemonfiber does not build is OSI-licensed. No Plex, no paid tiers, no phone-home. See service inventory. Our own code is Hippocratic 3.0, including the images lemonfiber builds for the stack — source-available and ethical-source, deliberately not OSI-approved.
Runs in slices Named forms map to sets of Compose profiles. search is 3 containers; full is 18. Same config, same data, no separate install.
Correct by construction The setup wizard tests hardlinks rather than assuming them. doctor compares public IPs to prove VPN isolation. Ports bind to loopback by default.

Who it’s for

Someone technical enough to run Docker but not interested in becoming an expert in six web UIs — plus the friend they hand it to afterwards, and the contributor who wants to add a service without touching Rust.

Where those needs conflict, ease of first setup wins. Existing tools already serve the tinkerer well; nothing serves the newcomer. That priority is why the wizard is a headline feature rather than a convenience, and why every interactive action must also have a non-interactive flag equivalent — so serving the newcomer never costs the scripter.

Design principles

These are load-bearing. When a decision is contested, resolve it against this list in order.

P1 — The filesystem contract is inviolable

Downloads and media live under one mount point so hardlinks and atomic moves work. Any design that risks breaking this is rejected regardless of other merits. Violating it turns every import into a full copy: slow, disk-doubling, and it breaks seeding by changing the inode. See ADR-0006.

P2 — Partial stacks are first-class, not degraded

lemonfiber up search is a supported mode with its own docs and tests, not “the full stack minus things.” No service may hard-depend on a service outside its own profile. See ADR-0002.

P3 — The tool proves things rather than assuming them

Where a claim is checkable, check it. Hardlink support: create one and stat it. VPN isolation: compare public IPs from inside both containers. Port availability: bind it. Assumptions stated in a README are documentation; assertions in doctor are engineering.

P4 — Errors carry remedies

Every user-facing failure names the fix. Error: hardlinks unsupported is a dead end. DATA_ROOT is on an exFAT volume, which cannot hardlink — imports will copy instead. Move it to an APFS volume, or accept slower imports (Settings → Media Management → Copy). is a tool.

P5 — Secure by default, not by configuration

The default posture must be the safe one, because defaults are what people run.

Binding is two-tier: administrative surfaces — the *arrs, download clients, and lemonfiber’s own control surface — bind to 127.0.0.1. Household-facing surfaces — Jellyfin, Seerr, the book and audiobook readers — bind to the LAN, because they are useless if a television cannot reach them.

Nothing binds to all interfaces. Exposing the control surface beyond loopback is refused unless authentication is configured, rather than warned about. Only Gluetun gets NET_ADMIN. Image tags are pinned.

See C6.

P6 — Reproducible over precious

rm -rf the config directory and rebuild in two minutes via lemonfiber seed. State that can be regenerated doesn’t need to be feared. This is what makes upgrades and experimentation safe.

Non-goals

Named explicitly so they’re rejected on purpose rather than forgotten.

Non-goal Why
Multi-tenant operation Several households sharing one stack. A single household with several members is in scope — see below.
Kubernetes / Nomad Compose is correct at this scale. Orchestrators multiply the platform matrix for no single-household benefit. (A Docker-optional runtime — Podman, and a native profile — is scheduled for 0.23.0, deliberately reopened by ADR-0010; it is out of scope for the single-engine assumption this line is about.)
Managing content acquisition policy lemonfiber wires the tools together. What you point them at is yours.
Being a general Docker manager Lazydocker exists. lemonfiber knows about this stack, and that knowledge is the value.
Windows without WSL2 Docker Desktop requires it. Supporting Hyper-V-only setups isn’t worth the matrix.
Media backup Configuration is backed up; a terabyte library is a job for a general-purpose backup tool.

Deferred, not rejected

Deferred Status
Remote access for the household Watching from outside the home. Deferred because every easy candidate had a proprietary control plane (Tailscale). It is scheduled for 0.22.0 as I1, built on a self-hosted overlay (Headscale + self-hosted relay). Household features stay LAN-only until it lands. See roadmap.

Formerly non-goals

Household support was originally out of scope. It isn’t: for a partner or housemate, the product is Seerr and Jellyfin, and they never see lemonfiber at all. That audience is now first-class — see D4, D6 and J9.

What success looks like

  1. A competent developer who has never used Sonarr gets to a working TV setup in under 15 minutes, without opening a service web UI to wire anything up.
  2. lemonfiber doctor catches a leaking VPN before any torrent traffic flows.
  3. Deleting the config directory and re-running lemonfiber seed restores a working stack in under 2 minutes.
  4. A household member is watching on their own device having received one link, with one account, and having never encountered lemonfiber.
  5. The same binary and the same commands work on macOS, Linux, and Windows.