Deployment¶
How Lightfall is deployed at a facility and at a beamline: which services run once per facility, which run per beamline, and exactly what must be configured today. Lightfall is in testing at the COSMIC-Scattering beamline at the ALS — a production-class deployment scoped to a single beamline while the platform matures.
Note
A turnkey beamline profile (one file that captures a beamline’s full configuration) and a provisioning runbook are on the roadmap. Today, deployment means standing up the services below and setting preferences in each Lightfall installation by hand. This page documents what exists now.
Topology: facility vs. beamline¶
Most of the stack runs once per facility and is shared by every beamline:
Service |
Role |
Notes |
|---|---|---|
Keycloak |
Single sign-on; identity for both control and data access |
Lightfall authenticates via OIDC and maps Keycloak groups/roles to application roles |
Tiled server |
Data catalog; per-entry access enforcement |
The auth-v2 API-key contract ( |
Logbook server |
Facility logbook backend |
Lightfall’s |
Error tracking |
Sentry-compatible server (the ALS runs self-hosted GlitchTip) |
Optional; telemetry is disabled unless a DSN is configured |
Git hosting |
Repositories for beamline plugin packages |
Any git forge; plugin packages are ordinary Python packages |
Each beamline runs its own:
Component |
Role |
Notes |
|---|---|---|
Lightfall GUI |
The application itself, one process per operator console |
|
NATS subjects |
The beamline’s slice of the message bus |
The broker itself can be shared facility-wide (bcgnats); beamlines are separated by topic prefix (e.g. |
EPICS IOCs / devices |
The actual hardware layer |
Lightfall coexists with existing control systems — both address the same EPICS process variables over Channel Access, so adoption can be incremental |
Beamline plugin repository |
Beamline-specific panels, plans, settings, themes |
Installed into the Lightfall environment as a Python package; see External Packages |
Autonomous engine (optional) |
e.g. Tsuchinoko for adaptive experiments |
Connects over NATS like any external client |
What must be configured today¶
Preferences (per installation)¶
User-facing settings live in PreferencesManager and are edited in the Preferences dialog (File → Settings). The keys below are the deployment-relevant ones, verified against src/lightfall/ui/preferences/:
IPC / NATS (ipc_settings.py):
Key |
Default |
Description |
|---|---|---|
|
|
NATS broker URL; an empty string disables IPC entirely |
|
|
Prefix prepended to every published/subscribed subject — set this per beamline |
|
(empty) |
Human-readable name for this instance, shown to discovery clients |
bcgnats authorizes every connection through a stateless auth callout (nats-auth-callout.service on the broker host). A client must send a random capability secret as its connect token and connect with the matching _INBOX.<p> inbox prefix; Lightfall does this automatically, and so do the updated beamline services. A client that doesn’t (an old build, a stock nats CLI without --token and --inbox-prefix) is rejected or can’t receive replies. Nothing has to be configured per installation and no credentials are issued. The bundled local broker (LocalNatsServer, 127.0.0.1 only) has no callout and trusts the host. Details: NATS Use Model.
Tiled (tiled_settings.py):
Key |
Default |
Description |
|---|---|---|
|
|
Enable the Tiled connection |
|
|
Tiled server URL |
|
|
|
|
(empty) |
Static API key, used when not authenticating via Keycloak |
|
(empty) |
Beamline identifier used in access tags and ESAF lookup |
|
|
alshub API used to resolve the active ESAF for access stamping |
Logbook (logbook_settings.py):
Key |
Default |
Description |
|---|---|---|
|
|
Enable the logbook subsystem |
|
|
Facility logbook server; entries are stored locally and synced here |
|
|
Keep entries local-only (no server sync) |
Devices (device_settings.py): a list of backend rows. Each row has a type, a unique name (its key in the device catalog), an enabled flag and type-specific settings. You can add several rows of the same type.
device_backends:
- {id: 3f2a…, type: mock, name: mock, enabled: true, config: {include_noisy: true}}
- {id: 9c1d…, type: happi, name: happi, enabled: true, config: {path: /data/happi.json, beamline: ""}}
- {id: 77be…, type: csm, name: csm-7011, enabled: true,
config: {url: https://bcgmgmt.als.lbl.gov, beamline_id: 12, beamline_name: 7.0.1.1,
ioc_id: null, ioc_name: null, name_filter: "", regex: false, include_inactive: false}}
Type |
Config keys |
|---|---|
|
|
|
|
|
|
|
|
CSM rows load after login using a personal CSM API key Lightfall mints at login (auth-v2, like Tiled and the logbook). The facility CSM (csm_url, default https://bcgmgmt.als.lbl.gov) is minted at every login, plus any other URL a CSM row names; a row on a new URL needs one more login before its lists load. Beam paths for a CSM row’s beamline are stored on CSM, where maintainer level or above on that beamline (including its scientist, owner) may create and change them. CSM must accept Lightfall’s client id (LUCID) for the mint. From Lightfall, CSM rows may change only display metadata (display_name, icon_override, group, synoptic, scope data) and never delete instantiables.
On first start after upgrading, the legacy device_backend / device_{mock,bcs,happi}_* keys are migrated once into device_backends. The old keys are left in place but no longer read.
Connection behavior is tunable via device_instantiate_mode (default background), device_connection_timeout (default 5.0 s), and device_connect_on_startup (default true). For off-site use, the same page configures the CA tunnel (Enable CA tunnel for remote access plus a gateway address, default localhost:5099) — see Remote EPICS Access.
Authentication (YAML config)¶
The auth provider is configured in the layered YAML configuration (application.yaml), not in Preferences. Files merge in priority order: bundled package defaults → system-wide (/etc/ncs/ or %PROGRAMDATA%\ncs\) → per-user (~/.config/ncs/ or %APPDATA%\ncs\) → runtime session overrides.
auth:
provider:
type: keycloak # local | keycloak | pam
server_url: https://keycloak.example.org
realm: alsncs
client_id: LUCID
redirect_uri: http://localhost:8089/callback
Field names and defaults are defined in lightfall.config.schema.AuthProviderConfig. The NCS_AUTH environment variable overrides the provider type at launch (e.g. NCS_AUTH=local for development). With no Keycloak configured, local auth and guest login keep the application usable.
Telemetry (opt-in)¶
Error reporting is disabled unless a DSN is explicitly configured — there is no default endpoint. Provide one via either:
the
SENTRY_DSNenvironment variable (wins), orthe
telemetry_dsnpreference.
Any Sentry-compatible server works. With no DSN set, all reporting functions no-op.
Agent credentials¶
The embedded Claude agent needs Anthropic credentials on each machine: set the ANTHROPIC_API_KEY environment variable, or authenticate a Claude subscription with the Claude Code CLI (claude auth login). Everything else in the application works without it.
A minimal single-machine deployment¶
For evaluation, none of the facility services are required: install, launch, continue as guest, and use the mock device backend. Adding services is incremental from there —
Tiled — point
tiled_urlat a Tiled server; runs are cataloged and browseable. For evaluation, a stock local server works with the API-key auth mode:pip install "tiled[server]", thentiled serve catalog --temp --api-key=secret(see Your First Session).NATS — point
ipc_nats_urlat a broker and choose aipc_topic_prefix; external clients can now submit plans and watch runs. Against bcgnats, clients must use the connection capability described in the NATS Use Model.Keycloak — configure
auth.providerin YAML; logins now mint per-service API keys, and runs are access-stamped per user and ESAF.Logbook server — point
logbook_urlat the facility logbook; local entries begin syncing.Telemetry — set a DSN once an error-tracking server exists.
Preference changes for the IPC service take effect on the next restart; the service is not reconfigured at runtime.