Working on the UI
This page is for contributors working on Lombok’s main web frontend.
It covers where UI code lives, how to run it locally, and how to keep it consistent with the rest of the codebase. It does not repeat environment setup — for that, start with Local Development with dx.
If instead you are building a UI for an app that embeds into Lombok, that is a different surface — see Where UI work lives below and the app-platform pages it links to.
Where UI work lives
Section titled “Where UI work lives”Lombok is a Bun workspace monorepo, so UI work is not in a single src/
folder. The main anchors are:
packages/ui— the main React + Vite frontendpackages/ui-toolkit— the shared UI component and design-system packagepackages/app-browser-sdk— the browser-side SDK for embedded app UIs
These map to different responsibilities. The main frontend in packages/ui is
responsible for:
- authenticated and unauthenticated app shells
- page routing with React Router
- sidebar and app UI rendering
- API- and socket-backed user interactions
For the broader map, see Package Map and Repository Conventions.
Main UI vs. embedded app UI
Section titled “Main UI vs. embedded app UI”Lombok has two distinct UI surfaces, and they are a real runtime and trust boundary — not just a visual distinction:
- the main platform UI in
packages/ui - embedded app UIs, which run inside an iframe/messaging boundary
This page is about the main platform UI. If you are working on an embedded app UI, you want a different set of docs:
The boundary between these surfaces is described in Runtime Boundaries and Architecture Overview.
Running the UI locally
Section titled “Running the UI locally”UI development uses the same Docker-based local loop as the rest of the
repository, driven by the ./dx developer CLI. The full setup — prerequisites,
./dx up, and the /etc/hosts entry — is documented in
Local Development with dx; this page
does not duplicate it.
Once your environment is running, the frontend is served at:
http://localhost:5173To restart just the UI service:
./dx restart uiFor the full list of ./dx commands, run:
./dx helpThe shared UI Toolkit
Section titled “The shared UI Toolkit”Before building a new component in packages/ui, check whether it already
belongs in the shared toolkit.
@lombokapp/ui-toolkit is Lombok’s reusable UI component and design-system
package, built around Radix, Tailwind, and Storybook. Use it when
you want:
- reusable UI components
- Lombok-aligned visual patterns
- shared presentation primitives
- consistency across internal and app-facing UI work
Keeping shared building blocks in the toolkit avoids treating every UI surface as a one-off implementation. See the UI Toolkit page for more detail.
How the UI talks to the backend
Section titled “How the UI talks to the backend”The browser is a client of the backend, not the system of record. The main UI reaches Lombok through:
- authenticated HTTP/API calls
- realtime Socket.io communication
- browser sessions backed by platform auth
Keep this boundary in mind when adding features: state and platform data come from the API, and realtime updates arrive over sockets. See Runtime Boundaries for the full picture.
Checks and tests
Section titled “Checks and tests”Use ./dx for the standard contributor checks. Linting, formatting, and
type-checking are shared across the monorepo:
./dx check all./dx check eslint./dx check prettier./dx check tscRun unit tests for a package, and the UI end-to-end suite, with:
./dx unit ui./dx e2e uiRefer to Local Development with dx for how these commands fit into the wider workflow. Dedicated pages for tests and linting/type-checking are planned for this docs wave.
Contributor mental model
Section titled “Contributor mental model”When deciding where a UI change belongs:
- a page, route, shell, or platform-specific view →
packages/ui - a reusable component or design primitive →
packages/ui-toolkit - anything that runs inside an embedded app → the app-platform UI surface and
App Browser SDK, not
packages/ui
Lombok is organized by runtime responsibility rather than by a single app folder, so matching your change to the right package keeps the boundaries clean.