Skip to content

lemonfiber-web — the web surface

lemonfiber

Lemonfiber — lemonfiber-web

lemonfiber's web interface: a console for the person who runs the stack, and a view for everyone else in the household.

Licence


This is the browser interface to a lemonfiber stack. You do not install it on its own: the lemonfiber binary carries a built copy and serves it.

Terminal window
$ lemonfiber ui
lemonfiber is serving at:
http://[::1]:49596
http://127.0.0.1:49596
…
The token for this run, which the page will ask you for:
417284f4…

Open the address, paste the token, and sign in. lemonfiber ui --help lists the options, such as --lan to offer it to your network.

Status: the console offers part of what the command line can do. docs/surface-parity.md lists every request and every kind of answer it does not offer yet.

It is a static application with no server of its own. It gets every piece of data from lemonfiber’s local web API, through the @lemonfiber/sdk-ts client, and reaches nothing else: no CDN, no font host, no analytics. It decides nothing itself; it asks lemonfiber and draws the answer.

On a version tag, publish.yml pushes the build output to a built-<tag> tag. The lemonfiber repository pins one of those tags as a submodule at assets/web and embeds it in the binary. The build declares the API version it speaks in app.json, and the binary refuses to compile against an app that speaks a version it does not serve.

The application serves two audiences, and they are not the same interface with things hidden:

  • The console — an operator’s view. State, checks, logs, services, setup, household administration.
  • The household view — what everyone else gets. What they asked for and where each request stands, whether asking needs approval and how much allowance is left, what they can watch, and what the household holds that they can.

Both are built from one component library and one set of tokens, so they cannot drift apart visually. What differs is which of them a given person is served, and that is decided by who signed in: one form takes the operator’s password and a household member’s, and lemonfiber’s answer names the member or nobody. Neither the address nor a setting chooses, and neither view holds a permission — lemonfiber refuses whatever a session may not have, whichever view sent it.

You need Node 26 or newer (engines in package.json).

Terminal window
npm ci
npm run dev

The dev server draws the shell and the empty states only. It has no back end and no proxy: the page asks lemonfiber at its own address. To see real data, serve your build through the binary: just ready (once, to build the client), then npm run build and lemonfiber ui --assets dist.

npm ci also turns on the repository’s git hooks.

Terminal window
just ready # once per clone, and again whenever the SDK moves
npm run ci

npm run ci is exactly what the gate job runs, which is the whole of CI over this repository’s own source — and it is not the whole of CI. gate.yml does two things first that are not in the chain: npm run client builds the SDK this surface is drawn through, and playwright install fetches the browser the accessibility sweep drives. Without them the eleven steps run, reach a11y, and fail there. just ready is those two, and just ci depends on it.

What the command leaves out is named in the justfile beside just ci: the four commit rules, which .githooks/commit-msg refuses before the push; sdk-drift, which compares every revision this surface pins in another lemonfiber repository with that repository’s default branch and with the lockfile; and the forge-side jobs.

The individual steps are the scripts in package.json, and each runs on its own while you work — npm test for the fast loop, npm run storybook to build a component in isolation, and npm run a11y to sweep every built story in a browser (after npm run storybook:build).

The lemonfiber repository’s standards apply here, in their web equivalents: 100% coverage across lines, statements, branches and functions; strict TypeScript with any and non-null assertions banned; zero lint warnings tolerated; architecture and file-size guards; every Svelte a11y_ warning refused at the compile, and accessibility asserted in the component tests and swept over every built story in a browser. The spec page maps each one to the workspace rule it mirrors.

From What
@lemonfiber/sdk-ts State, actions and the event stream, over the web API; and the wire version the build declares
@lemonfiber/brand Colour, type, spacing, radii, the logo — at build time

Both are pinned in package.json; that file is the version of record, so nothing here restates it.

The type is the one thing not embedded. src/app.css names Golos Text for the interface, Bricolage Grotesque for the wordmark and DM Mono for figures, and no @font-face ships here — @lemonfiber/brand owns type and gives this repo the tokens rather than the files. So each of the three falls back to the platform’s own stack wherever the face is not installed, and the interface looks the same across Linux, Windows and macOS in everything but its lettering.

Every change cites a requirement in the specification; routine maintenance cites GOV-R12. The spec page for this repository explains why it is shaped this way. Read the contributing guide and AGENTS.md first.

Support · Security · Code of conduct

Hippocratic License 3.0 — ethical-source, source-available, deliberately not OSI-approved. See the rationale.

lemonfiber is made by NightWorksIO.


NightWorks.io  · Discord

This page lives in another repository Rendered from lemonfiber/lemonfiber-web at 6de5d46, 2026-10-27. Read the source of this page