← The specification

Per-repo specifications

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

Status: Accepted

The diagram, the repository table and the sentence counting it are generated from repos.toml by scripts/gen_repos.py — edit the registry, not the page. just repos rewrites them and just generated refuses a hand edit. The prose around them is written by hand.

Where 20-architecture describes the system, this section describes each repository — its structure, its rules, and what is specific to working inside it.


The repos

flowchart TD
    spec["spec<br/>canonical"]
    gh[".github<br/>community health files"]

    subgraph impl[Implementation]
        lemonfiber["lemonfiber<br/>Rust binary"]
        web["lemonfiber-web<br/>the web surface"]
        companion["lemonfiber-companion<br/>the phone surface"]
        sdk["sdk-ts<br/>the TypeScript client"]
        sdkphp["sdk-php<br/>the PHP client"]
        sdkpy["sdk-python<br/>the Python client"]
        homeassistant["integration-home-assistant<br/>lemonfiber in Home Assistant"]
        mcp["integration-mcp<br/>lemonfiber for AI assistants"]
        stack["lemonfiber-media-stack<br/>retiring"]
        decline["lemonfiber-decline<br/>the decline service"]
        gate["lemonfiber-request-gate<br/>the request gate"]
        plugins["lemonfiber-plugins<br/>the reviewed catalogue"]
        servarrkit["adapter-kit-servarr<br/>what the Servarr adapters share"]
        tap["homebrew-tap<br/>generated formula"]
        site["website-lemonfiber.app<br/>the public frontpage"]
        docs["website-docs.lemonfiber.app<br/>the documentation site"]
        contribute["website-contribute.lemonfiber.app<br/>the contributor site"]
        kit["website-kit<br/>what both sites run"]
        lfdev["tool-lfdev<br/>the developer command line"]
        brand["brand<br/>design tokens"]
        parts["plugin-*<br/>twenty-one first-party plugins"]
    end

    web -->|submodule, pinned| lemonfiber
    sdk -->|pinned| web
    lemonfiber -->|contract artefact| sdk
    lemonfiber -->|contract artefact| sdkphp
    companion -->|pinned; every call goes through it| sdkphp
    lemonfiber -->|contract artefact| sdkpy
    homeassistant -->|vendored at a pinned commit| sdkpy
    mcp -->|vendored at a pinned commit| sdkpy
    plugins -->|submodule, pinned; the bundle embedded| lemonfiber
    plugins -->|bundle pins a revision and its tree| parts
    lemonfiber -->|release CI generates| tap
    brand -->|values mirrored| site
    lemonfiber -->|docs submodule, pinned| docs
    brand -->|docs submodule, pinned| docs
    spec -->|board snapshot, specification| site
    spec -->|board snapshot| lfdev
    lemonfiber -->|docs submodule, pinned| contribute
    servarrkit -->|taken by commit by the Servarr adapters| parts
    kit -->|taken by commit| docs
    kit -->|taken by commit| contribute
    gh -.->|inherited by| impl
    spec -.->|governs all| impl
Repo Spec Language What’s specific about it
spec ../README.md Markdown This repository — canonical, and cited by every change to the rest
lemonfiber lemonfiber.md · lemonfiber-tui.md · lemonfiber-reference.md Rust Three surfaces, one core; the submodule; the build
lemonfiber-web lemonfiber-web.md TypeScript Two surfaces, one component library; draws the API, implements nothing
lemonfiber-companion lemonfiber-companion.md PHP The fourth surface, and the first that does not run on the machine it operates
sdk-ts sdk-ts.md TypeScript Owns the stream’s hard parts so no consumer reimplements them
sdk-php sdk-php.md PHP The same contract, implemented as a peer rather than translated
sdk-python sdk-python.md Python An asynchronous and a synchronous client over one generated contract
integration-home-assistant integration-home-assistant.md Python The first program to hold an integration key rather than a person’s credential
integration-mcp integration-mcp.md Python Every tool generated from the contract, so an assistant can do nothing the web API does not offer
lemonfiber-media-stack lemonfiber-media-stack.md YAML/TOML Retiring (ADR-0045): each part is a plugin’s repository, and this is archived once the compose cutover reads none of it
lemonfiber-decline lemonfiber-decline.md Rust An image the stack runs, declared in a plugin.toml of its own; holds one Jellyfin key and answers the household
lemonfiber-request-gate lemonfiber-request-gate.md Rust An image the stack runs, declared in a plugin.toml of its own; holds the *arr keys and publishes no port
lemonfiber-plugins lemonfiber-plugins.md TOML Reviewed and signed, and never a runtime dependency
plugin-jellyfin first-party-plugins.md Rust The bundle’s media server: an adapter image in front of Jellyfin, so the train tags it
plugin-prowlarr first-party-plugins.md Rust The bundle’s part for the indexer manager, Prowlarr: an adapter image in front of the upstream’s, which is pinned by revision, so the train tags it
plugin-flaresolverr first-party-plugins.md TOML The bundle’s part for the solver that gets past an indexer’s bot protection, FlareSolverr; its image is the upstream’s, pinned by revision
plugin-nzbhydra2 first-party-plugins.md Rust The bundle’s part for the Usenet indexer search, NZBHydra2: an adapter image in front of the upstream’s, which is pinned by revision, so the train tags it
plugin-sabnzbd first-party-plugins.md Rust The bundle’s part for the Usenet download client, SABnzbd: an adapter image in front of the upstream’s, which is pinned by revision, so the train tags it
plugin-gluetun first-party-plugins.md TOML The bundle’s part for the egress guard, Gluetun, and the one part taking the egress-guard shape; its image is the upstream’s, pinned by revision
plugin-qbittorrent first-party-plugins.md Rust The bundle’s part for the torrent client, qBittorrent, run inside the egress guard’s network: an adapter image in front of the upstream’s, which is pinned by revision, so the train tags it
plugin-sonarr first-party-plugins.md Rust The bundle’s part for the television curator, Sonarr: an adapter image in front of the upstream’s, which is pinned by revision, so the train tags it
plugin-radarr first-party-plugins.md Rust The bundle’s part for the film curator, Radarr: an adapter image in front of the upstream’s, which is pinned by revision, so the train tags it
plugin-lidarr first-party-plugins.md Rust The bundle’s part for the music curator, Lidarr: an adapter image in front of the upstream’s, which is pinned by revision, so the train tags it
plugin-bindery first-party-plugins.md TOML The bundle’s part for the book curator, Bindery; its image is the upstream’s, pinned by revision
plugin-bazarr first-party-plugins.md Rust The bundle’s part for the subtitle fetcher, Bazarr: an adapter image in front of the upstream’s, which is pinned by revision, so the train tags it
plugin-recyclarr first-party-plugins.md TOML The bundle’s part for quality sync, Recyclarr; its image is the upstream’s, pinned by revision
plugin-unpackerr first-party-plugins.md TOML The bundle’s part for archive extraction, Unpackerr; its image is the upstream’s, pinned by revision
plugin-seerr first-party-plugins.md Rust The bundle’s part for the request service, Seerr: an adapter image in front of the upstream’s, which is pinned by revision, so the train tags it
plugin-calibre-web-automated first-party-plugins.md TOML The bundle’s part for the book library, Calibre-Web Automated; its image is the upstream’s, pinned by revision
plugin-audiobookshelf first-party-plugins.md TOML The bundle’s part for the audiobook server, Audiobookshelf; its image is the upstream’s, pinned by revision
plugin-navidrome first-party-plugins.md TOML The bundle’s part for the music server, Navidrome; its image is the upstream’s, pinned by revision
plugin-homepage first-party-plugins.md TOML The bundle’s part for the dashboard, Homepage; its image is the upstream’s, pinned by revision
plugin-door first-party-plugins.md Dockerfile The bundle’s part for the guarded door, Caddy rebuilt without its file capability; builds its image, so the train tags it
plugin-caddy first-party-plugins.md Dockerfile The bundle’s part for the proxy, Caddy rebuilt without its file capability, listening on 8080 and 8443; builds its image, so the train tags it
adapter-kit-servarr adapter-kit-servarr.md Rust One copy of the Servarr client, taken by each Servarr adapter at a commit
homebrew-tap homebrew-tap.md Ruby Generated; exists so brew works
website-lemonfiber.app website-lemonfiber.md Astro The org is the motor; roadmap read, not written
website-docs.lemonfiber.app website-docs.md Astro It renders; it does not own — every page pinned to the repo that wrote it
website-contribute.lemonfiber.app website-contribute.md Astro How to change the code; links to the rules on the frontpage rather than rendering them
website-kit website-kit.md TypeScript One copy of the mirror machinery, taken by each site at a commit
tool-lfdev tool-lfdev.md Python Every write is a pull request under the person’s own credentials
brand brand.md CSS/SVG Tokens are generated; the marks are not open
.github this page Markdown Org-wide community health files; no spec of its own

Those forty-three are the repositories this specification governs, which is not the same as every repository in the organisation and is no longer close to it. A plugin is a repository too, and where one comes from is the reviewed catalogue’s to answer (F5) rather than this register’s — so the org has repositories this file does not list, on purpose, and the sentence says so rather than making a claim nothing checks. A first-party plugin is listed, because the bundle the core embeds pins it (first-party plugins), and the release train cuts it with the core where it builds an image (OPS-R86).

.github carries the community health files GitHub serves for a repo that does not define its own — the code of conduct, the security policy, the issue templates and the org profile — so a sibling repo inherits them rather than copying them (tooling).

The REPO-R namespace

Per-repo requirements use REPO-R## — obligations specific to one repository’s structure or tooling, distinct from behaviour (A2-R4), architecture (ARCH-R1), governance (GOV-R2) and quality (Q-R1).

The relationships that matter

lemonfiber-media-stack → lemonfiber (submodule). lemonfiber embeds a pinned commit of lemonfiber-media-stack and validates its schema_version at build time (ARCH-R6). They version independently; the pin says exactly which stack a given binary ships (versioning).

lemonfiber → homebrew-tap (generation). lemonfiber’s release CI regenerates the formula once the Homebrew publish job is enabled at 1.0.0 (L1-R3). The tap is downstream of every lemonfiber release and is otherwise inert.

The documented repos → website-docs.lemonfiber.app (submodules). The documentation site shows the .docs/, README and policy files of lemonfiber, lemonfiber-web, lemonfiber-companion, sdk-ts, sdk-php, lemonfiber-media-stack, lemonfiber-plugins, brand, homebrew-tap, .github and plugin-template, each pinned to an exact revision and rendered rather than copied (ADR-0015). The specification is not among them: it is rendered on the frontpage, at the revision the board snapshot read (ADR-0040).

The repositories a contributor works in → website-contribute.lemonfiber.app (submodules). The contributor site renders each repository’s README.md and AGENTS.md, the core’s architecture notes and the developer command line’s guide, pinned the same way, and links to the specification’s rules on the frontpage.

spec → website-lemonfiber.app and tool-lfdev (the board snapshot). The report publishes one snapshot of where every version stands; the frontpage renders it and the specification at the revision it read, and lfdev answers from the same file (board snapshot).

Everything ← spec (governance). No change to any of them lands without citing this repository (50-governance).

lemonfiber → the SDKs (generation). lemonfiber emits one contract artefact from its own serde types; sdk-ts and sdk-php generate their types from it and hand-write only behaviour (ADR-0014).

The one property to remember per repo

  • lemonfiber — logic cannot render. The core crate has no UI dependency, so a surface can never grow behaviour of its own.
  • lemonfiber-media-stack — it holds what the bundle has not moved yet, and retires once nothing reads it. The project lemonfiber writes from it runs under plain docker compose, which is what makes adopting the tool reversible.
  • homebrew-tap — nobody writes it by hand. It holds a placeholder until the publish job turns it into generated output, and exists only because Homebrew requires a repo of that name.
  • website-lemonfiber.app — the org is the motor. Roadmap and status are read from the org at build time, never hand-authored, so the page cannot drift from reality.
  • website-docs.lemonfiber.app — it renders; it does not own. Every page is another repo’s file at a revision the site names, so a wrong sentence is fixed where it was written.