← The specification

Repo: lemonfiber

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

Status: Accepted

The lemonfiber binary — CLI, TUI and web UI over one core. Rust, Hippocratic 3.0.

Implements: the operator-facing half of 10-functional, under the structure fixed in 20-architecture/component-model.


What this repo is

One binary, three surfaces, one core. It sets the stack up, runs it, and proves it’s working. It is not a general Docker manager (vision non-goals) — its value is that it knows about this stack.

Layout

lemonfiber/
├── Cargo.toml                  workspace
├── crates/
│   ├── lemonfiber/             bin — chooses a surface and runs it
│   │   ├── build.rs            validates submodule schema_version
│   │   ├── src/cli.rs          clap: subcommands, flags
│   │   ├── src/dashboard.rs    ratatui: the dashboard and the log viewer
│   │   ├── src/ui.rs           binds the socket the web surface is served on
│   │   ├── src/main.rs         surface selection
│   │   └── tests/              integration tests
│   ├── lemonfiber-api/         lib — axum: the JSON endpoints, and the frontend served
│   ├── lemonfiber-core/        lib — all logic, no UI
│   ├── lemonfiber-ports/       lib — the boundary and its vocabulary
│   ├── lemonfiber-adapters/    lib — the ports' implementations that reach outside the process
│   ├── lemonfiber-fixtures/    lib — the fakes for those traits
│   ├── lemonfiber-manifest/    lib — stack.toml
│   └── lemonfiber-plugin/      lib — plugin.toml, and the vocabularies a plugin names things from
├── assets/media-stack/         git submodule, embedded at build
├── assets/web/                 git submodule — the built web surface, embedded at build
├── contract/                   generated contracts: the web API, the plugin schema and vocabularies
├── reference/                  the generated command reference, error codes and release record
└── .docs/                      repo-local technical docs

Crate responsibilities are fixed in component-model; this doc covers what’s specific to building the repo.

.docs/ — repo-local documentation

Per the three-layer model, lemonfiber carries its own .docs/ tree for Rust-specific technical detail that is not a product decision (those live in this spec) and not a code comment.

lemonfiber/.docs/
├── 00-index.md
├── architecture/       how subsystems are built — the ports boundary, dispatch,
│                       the engine API, the embedded stack, the error model
└── conventions/        an index pointing at the comment policy, which is canonical in the spec

Code links here (Q-R5); these pages cite spec requirement IDs. This is the middle layer that keeps requirement IDs out of code comments (GOV-R6) while still connecting code to the spec.

Surface selection

flowchart TD
    start[lemonfiber invoked] --> args{subcommand?}
    args -->|"up/down/doctor/…"| cli[CLI path]
    args -->|"ui"| web[Start web server]
    args -->|none| tty{stdout a TTY?}
    tty -->|yes| conf{configured?}
    tty -->|no| help[Print help, exit]
    conf -->|yes| dash[TUI dashboard]
    conf -->|no| wiz[Offer setup]

This realises G1-R3 and G1-R4: bare invocation opens the TUI at a terminal and prints help when piped, never blocking on stdin.

Key dependencies

Crate Role Why
clap CLI parsing Derive; generates help and completions
ratatui + crossterm TUI ADR-0003; crossterm for real Windows support
axum Web server Minimal, tokio-native; lemonfiber-api, and the socket the lemonfiber crate binds
bollard Docker API Reads only; only in lemonfiber-adapters
tokio Async Shallow — component-model
reqwest Service HTTP Seed clients
serde + toml Manifest, config
etcetera Platform paths XDG / AppData / ~/Library; permissive dependencies throughout
include_dir Embed stack + web assets ADR-0005
thiserror Library errors lemonfiber-core
color-eyre Binary errors The lemonfiber crate only

unsafe is denied crate-wide (see code-standards).

The submodule

assets/media-stack is a git submodule pinned to a lemonfiber-media-stack commit. crates/lemonfiber/build.rs:

  1. Fails clearly if the submodule is empty (git submodule update --init).
  2. Parses stack.toml and fails the build if schema_version is unsupported (ARCH-R6).

So an incompatible stack/binary pairing cannot compile, let alone ship.

Build-time work

Step Produces
build.rs Schema validation; embedded stack
cargo build The binary

The app is built in lemonfiber-web’s own CI and tagged there; this repo carries the result as a pinned submodule and embeds it with include_dir! (ADR-0012). No Node toolchain enters the Rust build or the operator’s machine (ARCH-R19).

Configuration on disk

Path (Linux shown) Holds
~/.config/lemonfiber/ .env, expected-state baseline, journal
~/.local/share/lemonfiber/stack/ Materialised stack files
~/.local/share/lemonfiber/config/ Per-service config (the /config mounts)
~/.local/share/lemonfiber/backups/ Backup archives

Resolved via etcetera, so macOS and Windows get their conventional locations. --stack-dir overrides the stack path (F1-R3).

Testing posture

Most of lemonfiber-core is testable without Docker or a terminal, by design (ARCH-R11). Detail in testing-strategy; the load-bearing point:

  • Command construction is pure → golden-file tested across every form × every platform, no daemon.
  • Docker access is behind a trait → mockable.
  • Platform is one component → faked, so all four environments run from one machine (ARCH-R35).

What lives here vs. in the spec

Here (lemonfiber) Spec
How the render loop is built That it must not block (B3-R4)
Which crate parses TOML The manifest contract
The exact port-push shell mechanism That the port must be re-pushed (C2-R5)
Rust module structure That core cannot render (ARCH-R11)

Rule of thumb: what and why are the spec’s; how, in Rust is this repo’s .docs/.