UI
This page covers building custom UI bundles. If you only need to configure which UI a deployment serves, use Providers > UI.
UI bundles are static asset packages. Gestalt serves them under the path
prefixes configured in providers.ui.<name>.path. The built-in admin UI at
/admin remains available regardless of whether a custom UI bundle is
configured.
For local iteration, you can run a source UI bundle directly with the same provider-local commands used for plugins:
gestaltd provider validate --path ./ui
gestaltd provider dev --path ./uiWhen the UI is part of a plugin/ + sibling ui/ package layout, running
gestaltd provider dev from the plugin side also picks up that sibling UI
automatically for the local session.
A UI bundle is not a plugin in the executable sense. It contains no server-side code. Gestalt simply serves the static files from the asset root directory. The bundle talks to Gestalt through the same HTTP API and MCP endpoints that any other client would use.
Manifest
The Default UI manifest declares spec.assetRoot, which points to the directory containing the built static assets. The source field identifies the provider in the registry.
kind: ui
source: github.com/valon-technologies/gestalt-providers/ui/default
version: 0.0.1
displayName: Default UI
description: Default Gestalt UI bundle.
release:
build:
command:
- sh
- ./build.sh
spec:
assetRoot: out
routes:
- path: /
allowedRoles: [viewer, admin]
- path: /admin/*
allowedRoles: [admin]The assetRoot path is relative to the manifest file. It should contain the output of your frontend build (typically an index.html and accompanying JS, CSS, and image files).
spec.routes is optional unless a deployment binds the UI to
providers.ui.<name>.authorizationPolicy. In that case, Gestalt uses these
route rules to enforce role-based access before serving the mounted route or
its static assets. At least one route must cover /, and every route must
declare non-empty allowedRoles.
Build step
If your UI needs a build step before packaging, use release.build to run it automatically during gestaltd provider release. This runs before source-manifest preparation, so the built assets are included in the release archive.
The Default UI uses a shell script that runs npm ci && npm run build to produce the static output:
kind: ui
source: github.com/valon-technologies/gestalt-providers/ui/default
version: 0.0.1
release:
build:
command:
- npm
- run
- build
spec:
assetRoot: outThe command runs relative to the manifest directory. After the build completes, Gestalt packages everything under assetRoot into the release archive. You can use any build tool here — npm run build, vite build, next build && next export — as long as it writes output to the directory specified in assetRoot.
Configuring a UI bundle
Reference a UI bundle in the providers.ui map of the server config. During
development, point at the source manifest:
providers:
ui:
dashboard:
source: ./web-default/manifest.yaml
path: /dashboard
authorizationPolicy: dashboard_usersFor production, reference a published release metadata URL:
providers:
ui:
dashboard:
source: https://artifacts.example.com/ui/default/v0.0.1/provider-release.yaml
path: /dashboard
authorizationPolicy: dashboard_usersWhen a config references a published UI bundle, run gestaltd init to resolve
and prepare it. This writes lock state to gestalt.lock.json and extracts the
assets under .gestaltd/. After init, gestaltd serve --locked serves the
locked UI bundle from its configured path prefix. If the prepared UI files are
already present, Gestalt uses them directly; if they are missing, Gestalt can
materialize them from the lockfile at startup.
If providers.ui is omitted entirely, Gestalt runs headless with no public UI
bundles.
The admin UI
The built-in admin UI is always served at /admin, regardless of whether a
custom UI bundle is configured. It provides a management interface for users,
plugins, connections, and API tokens. Mounted bundles own only their
configured public prefixes.
Release
UI bundles use the same release system as provider packages:
gestaltd provider release --version 0.0.1Run this from the directory containing the manifest. If release.build is defined, the build command runs first, then Gestalt packages the manifest and the asset root into a release archive. See Releasing for details on release archives, tag resolution, and prepared state.
What to read next
- Releasing: release archives, tag resolution, and prepared state
- Configuration: full server config reference including
providers.ui