Glance README · Configuration · Widgets
This repository is a maintained, substantially extended distribution of Glance maintained by samcro1967.
It preserves the familiar Glance configuration model and user experience while extending the application across dashboard functionality, configuration and presentation, Custom API capabilities, refresh and runtime reliability, frontend architecture, provider and HTTP behavior, diagnostics and observability, regression protection, and controlled development and delivery.
Existing upstream Glance configurations are intended to remain compatible with this fork. Fork-specific configuration is additive unless explicitly documented otherwise, and existing built-in behavior is generally preserved when optional fork functionality is not configured.
The fork continues to track upstream Glance while intentionally minimizing unnecessary divergence. Its internal implementation and engineering infrastructure have evolved substantially where additional functionality, production reliability, maintainability, observability, or regression protection provide concrete benefit. Changes incorporated from existing upstream pull requests or other Glance-derived projects are identified below where applicable.
The result is intentionally still Glance rather than a separate incompatible application: configuration compatibility, recognizable behavior, upstream provenance, and continued upstream synchronization remain explicit project goals even where the underlying architecture and engineering practices now differ substantially.
Fork module identity — Uses github.com/samcro1967/glance as the Go module and build identity while retaining github.com/glanceapp/glance as the upstream project for attribution and ongoing upstream synchronization.
Fork releases preserve the latest incorporated upstream Glance release version and append a fork-specific release revision.
Release tags use the following format:
v<upstream-version>-samcro1967.r<revision>
For example:
v0.8.5-samcro1967.r001
v0.8.5-samcro1967.r002
The three-digit fork revision identifies formal releases of this fork against the same upstream release line. It is not a commit count. The revision begins at 001 for the first fork release associated with an upstream release and increments for subsequent fork releases.
When a newer upstream Glance release is incorporated, the fork revision resets to 001. For example, after incorporating upstream v0.8.6, the first corresponding fork release would be v0.8.6-samcro1967.r001.
The upstream version component represents the latest formal upstream release incorporated by the fork. The fork may also incorporate commits from upstream main made after that release. Therefore, each fork release records both the upstream release version and the exact upstream baseline commit for reproducibility.
The Git tag is the authoritative release version. Source builds default to the development version dev, while the formal release process injects the exact Git release tag into the Glance binary at build time. This avoids maintaining a separate version file that could drift from Git release history.
Formal releases are created only from a clean, synchronized main branch after repository validation. Repository Makefile targets derive and validate the next fork release version before creating and pushing the release tag. Pushing the release tag invokes the repository's existing GitHub Actions and GoReleaser release workflow.
Development changes first integrate through the protected dev branch. After validation, dev is promoted to the protected main branch through a pull request. Merging into main does not itself create a release or update the latest container image. A formal release is created explicitly from main with the repository release tooling.
Because the fork identifier follows the hyphen in the tag, fork releases are prerelease versions of the corresponding upstream version under Semantic Versioning precedence rules. Within this fork, these tags nevertheless represent formal fork releases rather than development or test builds.
The fork's differences from upstream span both user-visible functionality and underlying architecture. They are grouped here by responsibility so the major areas of divergence remain understandable while preserving provenance and implementation detail.
-
Stack widget — Adds the
stackwidget from upstream PR #765, allowing multiple widgets to be stacked vertically and treated as a single widget. -
Analog clock widget — Adds an
analog-clockwidget based on upstream PR #747, providing a theme-aware analog clock with optional date and AM/PM indicators, configurable numerical dial markers, and additional clocks for configured timezones. -
Nested groups — Allows
groupwidgets to contain othergroupwidgets, enabling multiple levels of tabbed navigation. -
Timer widget — Adds a browser-local
timerwidget for creating countdowns to specific dates and times. Timers can be added, edited, deleted, and reordered directly in the widget, persist in the browser's local storage, and update automatically as their target times approach or pass. -
Stopwatch widget — Adds a browser-local
stopwatchwidget for measuring elapsed time without requiring a backend refresh or external service. The stopwatch supports start, pause, reset, and lap recording, uses monotonic browser timing to avoid wall-clock adjustments affecting elapsed time, and participates in the standard frontend initialization and cleanup lifecycle so active animation work is released when widget content is replaced or removed. -
ICS Events widget — Adds a native
ics-eventswidget for displaying events from iCalendar (ICS) feeds. The widget fetches and parses calendar data server-side, supports configurable date ranges and event limits, handles recurring events and timezone-aware dates, and participates in the standard Glance caching, refresh, recovery, and live-update lifecycle. -
Calendar ICS sources — Extends the native
calendarwidget with optional generic iCalendar (ICS) sources, directly addressing the calendar use case requested in upstream issue #90 without coupling Glance to Radarr, Sonarr, or another application-specific API. Multiple URL or file sources can be combined, with server-side handling of recurring events, cancellations, overrides, all-day and timed events, timezones, conditional HTTP caching, partial-source failures, and the standard Glance refresh, recovery, and live-update lifecycle. Calendar months remain browser-local and immediately navigable across a bounded 25-month range, while dates display event counts and selectable days expose event details including time, title, source, location, and links. Source HTTP configuration participates in hierarchical widget defaults, and source URLs, authentication data, and other feed credentials are not exposed in the browser event payload. Applications such as Radarr and Sonarr can therefore be used through their existing ICS feeds while the Calendar integration itself remains provider-independent. Upstream issue #95 is related *Arr integration work but concerns recent releases/grabs rather than calendar events and is not implemented by this feature. -
Markdown widget — Adds a native
markdownwidget for rendering configured Markdown content using Glance styling. Markdown is rendered server-side with HTML sanitization and supports standard Markdown formatting without requiring an external service or Custom API endpoint. -
Unit Converter widget — Adds a native
unit-converterwidget for performing unit conversions directly in the browser without requiring an external service or network request. The widget provides 35 conversion categories and 379 units spanning common measurement, scientific, digital-information, electrical, and fuel-economy conversions. Category and unit selections update the result immediately as the input value changes. Conversion definitions are embedded with Glance and use scale, affine, and reciprocal transforms to support standard linear conversions, temperature conversions, and fuel-economy conversions while remaining fully self-contained. -
Calculator widget — Adds a native
calculatorwidget for performing calculations directly in the browser without requiring an external service or network request. The calculator provides standard arithmetic operations, percentage, reciprocal, square, square root, exponent, nth-root, parentheses, sign change, clear-entry, clear, and backspace controls, with operator precedence and keyboard input support. -
Astrology widget — Adds a native
astrologywidget built on the shared local ephemeris foundation, presenting tropical-zodiac Sun, Moon, and planet positions, retrograde state, major aspects, sign ingresses, and upcoming planetary stations without a remote astrology API. -
Astronomy widget — Adds a native
astronomywidget for locally calculated Sun, Moon, planet, bright-star, eclipse, meteor-shower, and upcoming sky-event information. Location names reuse Glance's cached Open-Meteo place resolution; explicit coordinates and timezone are also supported for network-independent operation. Celestial calculations use the Apache-2.0starainrt/astroGo library and refresh on the normal widget lifecycle without an astronomy API key. -
Horoscope widget — Adds a native
horoscopewidget for provider-backed daily, weekly, and monthly sun-sign readings. Signs are selected explicitly rather than derived from birth data,free-horoscope-apiis the default keyless provider, and a calendar-aware daily default schedule avoids unnecessary refreshes while preserving the standard Glance stale/retry/live-update lifecycle. -
Dilbert widget — Adds a native
dilbertwidget that retrieves archived Dilbert strip pages from the Internet Archive Wayback Machine, validates the requested comic date, extracts the rendered archived comic image with bounded fallback across unavailable captures, and participates in the standard Glance caching, cancellation, stale/degraded, and HTTP failure-classification lifecycle. The zero-configuration default selects a random comic from the supported 1989-04-16 through 2023-03-12 archive range, while an optional date can pin a specific strip. Comic images scale to the widget and use a shared click-to-enlarge viewer that is initialized and cleaned up through the normal live-widget frontend lifecycle. -
Named dashboards — Allows configured pages to be organized into multiple independently addressable dashboards with dashboard-specific navigation.
-
Medium page columns — Adds a
mediumpage column size for proportional desktop layouts. Threemediumcolumns create an equal three-column layout, whilemedium+fullcreates an approximately one-third/two-thirds layout and can be reversed asfull+medium. Existingsmallandfulllayouts remain unchanged, and medium columns use the standard one-column-at-a-time navigation on mobile. -
Fixed desktop navigation — Keeps the global desktop page navigation fixed to the top of the viewport while scrolling, independent of page length and surrounding layout. Dedicated document-flow spacing prevents page content from being obscured beneath the fixed navigation, while the configured header appearance and existing mobile navigation behavior are preserved.
-
Bottom widgets — Adds a
bottom-widgetspage section that mirrorshead-widgets, allowing standard Glance widgets to span the full page width below the configured columns. Bottom widgets participate in the same initialization, provider setup, refresh, caching, and recovery lifecycle as widgets elsewhere on the page. Existing configurations withoutbottom-widgetsremain unchanged. -
Footer micro-widgets — Adds compact, position-aware micro-widgets to the left and right sides of the standard Glance footer without occupying page columns. Supported types are Bookmark, Clock, Weather, Markets, Monitor, and Link. Dynamic Weather, Markets, and Monitor micro-widgets participate in the normal refresh lifecycle and share underlying provider resources where applicable, while Bookmark, Clock, and Link remain lightweight local presentation. Each side supports independently ordered positions with a configurable per-side limit, and the complete micro-widget layer is hidden on narrower layouts and whenever the standard footer is disabled.
-
Status Bar widget — Adds a compact full-width
status-barwidget for presenting Weather, Markets, RSS, and a locked compact Custom API data contract in either a continuously scrollingtickeror static wrappingwraplayout. Ticker mode supportsslow,normal, andfastspeed settings with width-normalized scrolling so Status Bars with different amounts of content move at a consistent visual rate. Hover and keyboard focus continue to pause scrolling, while mouse-activated links release focus so returning from a newly opened tab does not leave the ticker paused. Status Bar links use the standardopen-links-in-new-tabpolicy, which defaults totrue; the Status Bar owns this policy for its compact Markets, RSS, and Custom API links rather than inheriting potentially conflicting child-widget link settings. Status bars can be placed only directly inhead-widgetsorbottom-widgets; supported child widgets retain their normal configuration, provider fetching, caching, refresh, recovery, and error behavior while using dedicated compact renderers. Equivalent underlying Markets, Weather, and RSS resource requests are shared where applicable so adding a status bar does not unnecessarily duplicate provider requests already being made by another configured widget. -
Expanded Weather widget — Extends the native Weather widget with a comprehensive Open-Meteo dataset covering current conditions, compact weather details, the existing hourly temperature and precipitation visualization, and a fixed 7-day forecast. Current conditions, details, hourly data, and forecast sections can each be independently shown or hidden with
show-current,show-details,show-hourly, andshow-forecast, with all four enabled by default. Weather details include high and low temperatures, humidity, precipitation probability, wind, UV index, visibility, pressure, sunrise, and sunset, with metric and imperial presentation and configured 12-hour or 24-hour time formatting. Equivalent Weather requests continue to share provider resources independently of presentation settings, preserving existing caching behavior and Status Bar integration. -
Themed page-not-found response — Addresses upstream issue #1062 by replacing the plain-text response for unknown page URLs with a themed Glance 404 page that preserves HTTP 404 semantics and provides links to the configured pages available in the current dashboard. Dashboard paths and configured base URLs are preserved, while API page-content requests continue to return a plain HTTP 404.
-
Brave Search preset — Adds Brave Search to the native Search widget's built-in provider presets while preserving custom search-engine URLs and existing query handling. Adapted from
kirolos/glancecommit7b846b49. -
Clickable Video thumbnails — Makes Video widget thumbnails navigate to the same video as the title across card, grid, and vertical-list presentations while honoring the existing new-tab policy. Adapted from
grayespinoza/glancecommit23efccdf. -
Clickable Reddit thumbnails — Makes Reddit thumbnail images navigate to the post discussion across list and card presentations while preserving shared forum rendering for Hacker News and Lobsters and honoring the existing new-tab policy. Adapted from
grayespinoza/glancecommit6c055fea. -
Monitor site descriptions — Adds optional per-site descriptive text to the standard Monitor presentation with bounded single-line rendering; compact Monitor presentation remains unchanged. Adapted from
kirolos/glancecommit5e01e5d. -
Self-hosted Releases providers — Adds validated per-repository
base-urlsupport for GitLab and Codeberg-compatible Releases sources while preserving the public provider defaults and existing GitHub/Docker Hub behavior. Redesigned fromkirolos-esmat/glancecommit529f789b. -
Blocky DNS Stats provider — Extends the native DNS Stats provider abstraction with Blocky Prometheus-metrics support while reusing Glanze HTTP timeout, TLS, cancellation, status-error, and stale/degraded handling. Hardened from
kirolos-esmat/glancecommitc6dd5d7c. -
Control D DNS Stats provider — Extends DNS Stats with Control D reporting data, guarded zero-value calculations, bounded responses, cancellation, and existing HTTP failure semantics without the source implementation’s debug output. Hardened from
kirolos-esmat/glancecommitc1f49443. -
Prometheus widget — Adds a native PromQL range-query graph with units, scale/time labels, request headers, hover values, configurable range/step, shared timeout/TLS behavior, and deterministic single-series enforcement. Adapted and hardened from
chand1012/glancecommit21f10cdcand hover-tooltip follow-upa1d0dfce. -
Torrenting widget — Adds a native
torrentingwidget for qBittorrent, with API-key or session authentication, normalized torrent state, progress and ETA presentation, filtering, collapse controls, and Glance shared HTTP, cancellation, stale/degraded, and error-classification behavior. The initial provider adapter targets qBittorrent while keeping provider-specific authentication and response semantics isolated from the normalized widget model. -
ARR widget — Adds a native
arrwidget with isolated Radarr/Sonarr/Lidarr adapters, normalized upcoming/recent/missing presentation, API-key authentication kept server-side, shared HTTP cancellation/error semantics, and resource-proxied artwork. Radarr and Sonarr use API v3; Lidarr uses API v1. -
Seerr widget — Adds a native
seerrwidget for discovery, upcoming media, requests, recently added media, and watchlist views using Seerr API v1, server-side API-key authentication, shared HTTP cancellation/error semantics, and resource-proxied TMDB artwork. -
Latest Media widget — Adds a native
latest-mediawidget for newest library additions from Plex, Jellyfin, Emby, and Navidrome, with provider-specific authentication isolated behind a normalized media model and resource-proxied artwork. -
Media History widget — Adds a native
media-historywidget for Plex playback history and Jellyfin/Emby recently played state, reusing the normalized media model and server-side authentication/artwork handling established by Latest Media. -
Now Playing widget — Adds a native
now-playingwidget for active Plex, Jellyfin, Emby, and Navidrome sessions with normalized playback state, progress, client metadata, and resource-proxied artwork. -
Docker Compose project grouping — Adds opt-in
group-by: compose-projectpresentation to the Docker Containers widget using Docker's authoritativecom.docker.compose.projectmetadata. Existingglance.id/glance.parenthierarchy and filtering semantics remain unchanged, unlabeled top-level containers remain visible in an Ungrouped section, and no container-name or deployment heuristics are used. Redesigned fromToTt0G/glancecommit6528e8f. -
Application grid-card styles — Adds opt-in
style: grid-cardspresentation to the Bookmarks, Monitor, and Docker Containers widgets using a shared application-card layout. Cards remain square and automatically wrap according to the available widget width while preserving each widget's existing semantics: Bookmark groups remain separate, Monitor retains site status, response-time, andshow-failing-onlybehavior, and Docker retains container state, details popovers, hierarchy, filtering, and optionalgroup-by: compose-projectgrouping. Grid-card links open in a new tab, Docker cards without configured URLs remain non-navigable, and omittingstyle: grid-cardspreserves each widget's existing presentation unchanged.
-
Configuration fault isolation and source-aware diagnostics — Separates independently recoverable presentation and feature configuration errors from structural, security-sensitive, persistence, routing, and process-level failures. Invalid widgets and nested widget children retain their layout position through the standard error presentation while valid siblings continue to run; footer micro-widget failures are isolated the same way. Invalid analytics configuration disables analytics for that application generation, invalid global or page theme configuration falls back to a valid inherited/built-in theme, invalid named presets and type-specific widget-default blocks are omitted independently, invalid global widget defaults fall back to built-in behavior, and an unavailable custom assets path is disabled rather than preventing the dashboard from starting. These recoverable failures retain source-aware diagnostics and are logged without being silently accepted:
config:validateremains strict and exits nonzero. Malformed YAML, unresolved includes or configuration variables, invalid page/dashboard topology, authentication/authorization and proxy-security configuration, unsupported personal-state document versions, OIDC runtime initialization failures, and listener/server failures remain unrecoverable. Corrupt or empty personal-state files are quarantined with an explicit warning and an empty store is started so ancillary browser state cannot prevent the application from starting. Cold starts and restarts therefore continue whenever the invalid configuration can be safely isolated, while automatic reloads reject unrecoverable candidates and keep the currently active application generation serving. -
Hierarchical widget defaults — Adds optional
widget-defaultsconfiguration for defining shared widget settings once and inheriting them across the dashboard. Defaults can be defined globally and per widget type, with more specific configuration taking precedence over broader defaults and explicit widget or child/source settings taking precedence over inherited values. Supported shared capabilities include common widget presentation settings including title icons, caching settings, link behavior, list sizing and collapsing, and applicable HTTP request settings such as timeouts, TLS handling, headers, and authentication. Capabilities are applied only to widget types and configuration scopes for which they are semantically valid. Existing Glance configurations remain fully compatible:widget-defaultsis optional, existing widget-specific properties retain their current behavior, and built-in widget defaults remain unchanged when no hierarchical defaults are configured. Built-in values for shared configurable capabilities are resolved through the same hierarchy as configured defaults, establishing a single precedence contract of built-in, global, widget type, then explicit widget or child configuration while widget initialization retains validation and normalization ownership. -
Widget title icons — Adds the common
iconproperty to widget headers, allowing an optional icon to be displayed immediately before a widget title using direct image URLs or thesi:,sh:,di:,hla:, andmdi:icon-library syntax, withhla:providing Homelab SVG Assets and automatic inversion applied where applicable. Title icons participate in hierarchical widget defaults with global, type, and explicit widget precedence; an explicit empty icon suppresses an inherited value. Icons sharetitle-urllinks with their titles, are suppressed with hidden or empty headers, appear with child titles in Group tabs, and use normal child headers in Stack widgets. Existing widget-specific item and service icons remain independent. -
Page navigation icons — Adds an optional
iconproperty to pages, displaying the configured icon immediately before the page name in desktop and mobile navigation. Page icons use the same direct image URL andsi:,sh:,di:,hla:, andmdi:icon-library syntax as other Glance icons, including automatic inversion where applicable. The icon and page name remain part of the same navigation link and retain the existing active, inactive, hover, dashboard-routing, and configured base-URL behavior. Page icons are explicit per-page configuration rather than participating in widget defaults, and existing pages without an icon retain their previous navigation appearance. -
Expanded native themes — Expands Glance native theming from a small set of global colors into a semantic visual theme system covering colors, typography, page backgrounds, headers, navigation, widget surfaces and headers, cards, groups and tabs, controls and buttons, footers, elevated surfaces, separators, radii, shadows, and blur. The top-level
themeremains the configured default appearance, while individual pages can provide partial theme overrides that inherit all unspecified values from the selected base theme. The theme picker provides fully defined Glance Dark and Glance Light themes together with explicitly named user themes. The built-in themes use the same public semantic theme contract available to user configuration rather than relying on private theme-specific CSS, providing complete reference implementations for dark and light appearances. Theme values use validated, bounded configuration options, including local/assets/...page background images. Widget body typography also supports optionalfont-sizeandfont-weightoverrides, with unconfigured values inheriting from the corresponding global typography settings. Shared dashboard spacing also supports semanticcompact,normal,comfortable, andspaciousdensity profiles through the existing global and page-level theme hierarchy. Density adjusts common information spacing such as widget gaps and padding, headers, lists, cards, grids, tables, metrics, and key/value layouts without indiscriminately resizing typography, controls, media, charts, or specialized widget geometry; omitted density preserves the existing normal spacing baseline. Custom CSS is supported as independent global, selected-preset, and page layers after resolved native theme CSS, with deterministic cascade ordering and live preset-layer replacement when the browser theme picker changes themes. Existing theme configurations remain compatible. -
Unified presentation system — Adds a shared semantic presentation layer used across native widgets and Custom API content so common Glance interface concepts have one visual language instead of being independently styled by each widget. Reusable primitives cover list rows, cards, metrics, badges and statuses, key/value data, progress indicators, disclosures, grids, state presentation, tables, charts, form controls, buttons, icon buttons, tabs, secondary and muted text, and separators. Native widgets adopt these primitives where the presentation concept is genuinely shared, while specialized structures such as calendars, weather visualization, calculator geometry, market charts, status bars, media layouts, and widget-specific responsive behavior retain their own layout rules. Generic structural classes such as
listare deliberately not globally restyled; shared presentation is opt-in through Glance-owned semantic classes. Common surface hierarchy, typography, interaction states, focus behavior, selection language, spacing, radii, shadows, and theme values therefore remain centralized without forcing unrelated widgets through a generic component framework. The visual direction uses layered surfaces, restrained borders, clear typography hierarchy, and accent colors primarily for selected or actionable state while preserving Glance's information density. -
Custom CSS presentation architecture — Custom CSS follows the same presentation architecture without being merged into semantic theme resolution. The document emits stable global, selected-preset, and page stylesheet layers after resolved native theme CSS. Theme changes dynamically replace or remove only the selected-preset stylesheet while global and page styles remain active. User-defined
/assets/...stylesheet paths participate in configured base-URL resolution, and dynamically selected stylesheets use the same application-version cache-busting identity as initial page assets. -
OpenID Connect authentication — Adds generic OpenID Connect (OIDC) authentication alongside the existing local username/password mechanism. OIDC uses provider discovery, authorization-code flow protection with state, nonce, and PKCE, verified ID tokens, and the existing encrypted Glance session model. Local and OIDC authentication can coexist. An optional provider name controls login and current-user presentation, while an optional
allowed-userslist restricts access to exact case-insensitive verified email identities; omitting the list allows any successfully authenticated identity from the configured provider. OIDC configuration participates in normal application-generation reloads. Active OIDC sessions are rechecked against the currentallowed-userslist on every request, so removing an identity revokes access immediately; legacy OIDC session formats that do not carry a verified authorization identity must reauthenticate when an allowlist is configured. Authentication diagnostics use bounded stage and reason classifications without logging authorization codes, tokens, session material, OIDC subjects, email addresses, or claims payloads. Logout is exposed only as a POST action from the authenticated UI so cross-site top-level GET navigation cannot clear a session cookie. -
Dashboard authorization — Adds optional user- and group-based access control for named dashboards across local and OIDC authentication. Once dashboard access rules are configured, dashboards are deny-by-default and pages are accessible when they belong to at least one dashboard available to the authenticated identity. Unauthorized dashboards and pages are hidden from normal navigation and return HTTP 404 when addressed directly, while existing dashboard routing topology is preserved. Authorization policies participate in normal application-generation reloads and are applied to subsequent requests from existing authenticated sessions. Authorization is enforced consistently for dashboard/page routing, page content, direct widget-content requests, and live-update subscriptions. Static assets and opaque resource-proxy IDs remain application-level resources rather than per-dashboard objects, and this feature is not presented as general multi-tenant isolation. Operator-wide runtime diagnostics require access to every configured runtime dashboard rather than merely any authenticated session.
-
Optional web analytics — Adds optional first-party integration with self-hosted or hosted GoatCounter for privacy-conscious dashboard page-view analytics. Analytics are disabled by default and are enabled only when an
analyticsconfiguration is present with thegoatcounterprovider and an HTTP or HTTPS GoatCounter endpoint. Glance derives the GoatCounter collection and script URLs from the configured endpoint and loads GoatCounter's standard asynchronouscount.jsintegration on dashboard documents, allowing normal full-page dashboard navigation to be recorded without introducing a separate Glance tracking API or manual page-view implementation. Analytics failures remain isolated from dashboard, widget, refresh, degraded-state, retry, and diagnostics lifecycles so an unavailable analytics service cannot affect normal Glance operation. Endpoint configuration is validated and normalized during configuration loading, including rejection of credentials, paths, queries, fragments, relative URLs, and unsupported schemes. Existing configurations remain unchanged when analytics are omitted. Deployments using restrictive Content Security Policy rules remain responsible for permitting the configured analytics endpoint in the applicable browserscript-srcandconnect-srcpolicies.
-
Custom API timeouts — Adds configurable request timeouts to
custom-apiwidgets based on upstream PR #997, with independent timeout settings for primary requests and subrequests. -
Custom API string helpers — Adds template helpers for common string operations in
custom-apiwidgets, including case conversion, substring checks, prefix and suffix checks, case-insensitive comparison, splitting, and joining. -
Custom API dynamic request methods — Addresses upstream issue #800 and incorporates the implementation from upstream PR #801 by adding
withMethodfor dynamically created Custom API requests, allowing templates to explicitly select the HTTP request method while preserving the existing GET default and body-implies-POST behavior. -
Custom API stale fallback — Addresses the graceful Custom API error-handling use case described in upstream issue #823 by preserving the last successfully rendered
custom-apicontent when a refresh fails, displaying a visible stale indicator with the age of the last successful update, and automatically clearing the stale state after a successful refresh. -
Custom API dynamic-request lifecycle reliability — Binds template-created Custom API subrequests to the active widget refresh context so cancellation and shutdown propagate through dynamic requests instead of allowing them to continue independently. Transport, timeout, and malformed-response failures propagate through the standard widget failure, degraded, stale-content, retry, and recovery lifecycle, while non-success HTTP responses with usable bodies remain available to templates for intentional response inspection.
-
Custom API Sprout template functions — Extends the existing Custom API Go template environment with a curated set of 134 functions from Sprout v1.1.1, exposed under a
sproutprefix so existing Glance template helpers and their behavior remain fully compatible. Supported functions cover conversions, strings, slices, maps, regular expressions, numeric operations, defaults and other standard helpers, encoding, and semantic versions. The exposed surface is maintained through an explicit allowlist rather than automatically registering entire Sprout registries, excluding aliases and helpers involving environment access, filesystems, networking, randomness, cryptography, checksums, time, UUIDs, reflection, and deprecated regular-expression APIs. Sprout collection helpers operate directly on Custom API JSON arrays, while Glance-specific JSON, request, time, sorting, and other existing helpers remain unchanged. -
Custom API native presentation components — Adds an opt-in Glance-owned presentation layer for normal
custom-apitemplates while preserving complete compatibility with existing arbitrary HTML templates. Reusable semantic classes provide native metrics and statistics, badges, statuses, key/value layouts, cards, responsive grids, progress meters, disclosures, and empty, warning, error, and degraded states. Native tables use a Glance-owned declarative configuration for responsive behavior, sorting, search, pagination, page size, semantic column types, and responsive priorities, with DataTables vendored as a private implementation detail. Native charts provide line, area, bar, pie, doughnut, sparkline, and gauge visualizations through semantic Glance configuration and JSON data, with Chart.js vendored privately for rendering. Presentation components use the active Glance theme, participate in live widget replacement and cleanup, adapt to widget width, and isolate component failures so a failed enhancement does not replace otherwise usable Custom API content. Existing Custom API templates require no migration, third-party library configuration is not exposed as public API, and presentation data remains declarative rather than permitting executable scripts or runtime CDN dependencies. -
Alertmanager Custom API example — Addresses the Alertmanager dashboard use case requested in upstream issue #1082 through the existing Custom API architecture rather than introducing a provider-specific native widget. The maintained example consumes Alertmanager's native
/api/v2/alertsJSON response directly, renders active and suppressed alerts with severity, annotations, labels, receivers, relative start time, suppression state, and source links, and documents Alertmanager-side filtering and Glance authentication options. Deterministic fixture data and a browser-managed documentation screenshot keep the example covered by the existing visual documentation workflow without adding an external data producer or duplicate request lifecycle.
- Automatic widget recovery — Addresses upstream issue #921 by adding server-side background refresh and recovery for updateable widgets. Expired or previously failed widgets are retried automatically without requiring a page to be open or manually refreshed. Refreshes are synchronized per widget to prevent duplicate concurrent updates while preserving parallel updates across different widgets, use bounded concurrency and progressive retry backoff after failures, and are cancelled cleanly during shutdown and configuration reloads. Normal successful refresh timing continues to respect each widget's configured cache duration or cron schedule. The
custom-apiwidget additionally preserves its last successfully rendered content while a refresh is failing. - Cron-based widget refresh scheduling — Adds optional
cache-cronscheduling for refreshable widgets, addressing the wall-clock scheduling use case described in upstream issue #1081. Cron scheduling is an alternative to duration-basedcacheand uses the existing widget refresh lifecycle rather than introducing a separate scheduler or fetch path. Standard five-field cron expressions and wall-clock descriptors such as@hourlyand@dailyare supported; seconds,@every, and per-expression timezone prefixes are intentionally excluded. Schedules use the Glance process/container timezone. New and reloaded widgets remain immediately eligible for their initial refresh, successful and non-retryable refreshes advance to the next cron occurrence, and retryable failures retain the existing earlier retry behavior without scheduling beyond the next normal cron occurrence.cache-cronparticipates in hierarchical widget defaults using the same cache capability and precedence contract ascache, with more-specific configuration replacing the inherited scheduling form and same-levelcachepluscache-cronrejected as ambiguous. Invalid widget cron configuration participates in the existing source-aware configuration diagnostics, while configurations that omitcache-cronretain existing duration-based behavior unchanged. - Configuration watcher reliability — Hardens configuration file watching and reload behavior against concurrent shutdown and configuration-change activity. Debounce timer ownership is synchronized to prevent races between pending configuration notifications and watcher cleanup. Watcher shutdown also prevents new debounce work and waits for an already-running configuration callback to finish before returning, preventing configuration callbacks from continuing to mutate application state after watcher shutdown or during application teardown. The configuration loaded during startup is treated as the watcher baseline rather than generating an immediate duplicate change notification, avoiding an unnecessary replacement application generation at startup.
- Runtime lifecycle hardening — Expands synchronization and regression protection around application startup, shutdown, configuration reloads, background widget refreshes, resource caching, and watcher cleanup. The background scheduler is the sole owner of top-level widget refresh work, keeping provider requests out of page-content request latency and centralizing refresh, retry, cancellation, telemetry, and live-update behavior. Scheduler cancellation propagates cleanly to active work and shutdown waits for scheduler workers to finish. Nested aggregate refresh work in Container, ICS, and Custom API paths uses the existing bounded worker-pool infrastructure with a shared concurrency policy, preventing configuration-dependent inner fan-out from becoming unbounded while preserving ordering, cancellation, and partial-failure behavior. Configuration watcher cleanup waits for active callbacks. The process HTTP listener remains stable across configuration reloads while application generations are prepared and atomically swapped behind it: invalid replacement configurations leave the active generation serving, successful reloads route new requests to the replacement generation while allowing requests already executing on the previous generation to finish, and the retired generation's background scheduler and live-update resources are then stopped. Listener-defining
server.hostandserver.portchanges are rejected during reload and require restart. Process shutdown uses bounded graceful HTTP shutdown before falling back to a forced close, and the loopback profiling listener can be enabled or disabled independently without rebinding the main application listener. Initial HTTP bind failures occur before application background work begins. Shared Server Stats host metadata caching is synchronized for concurrent collection while preserving retry behavior after collection failures. Shared Yahoo Markets and Open-Meteo resource caches opportunistically remove entries that have been idle for 24 hours without evicting active in-flight requests, preventing abandoned configuration-derived cache keys from accumulating indefinitely in long-running processes. Idle-entry pruning is amortized rather than scanning the complete keyed cache on every access, keeping normal cache-hit cost effectively independent of cache size while retaining bounded cleanup of abandoned entries. Process-global shared provider fetches are isolated from individual application-generation cancellation: callers stop waiting when their own context is canceled without canceling an in-flight shared fetch that may still be needed by a replacement generation. Page-content requests render the currently available widget state rather than initiating provider refresh work. Successful rendering establishes a committed widget HTML snapshot, allowing page rendering to reuse that snapshot while a refresh owns the widget synchronization boundary instead of waiting on provider network I/O; widgets without an initial snapshot retain first-render synchronization. - Widget render failure fallback — Preserves visible failure reporting when a widget-specific template fails during both its normal render and error-state render. Glance falls back to the standard widget error presentation with the original failure retained instead of returning empty or partially rendered widget markup.
- HTTP server startup failure handling — Incorporates upstream PR #1047, addressing upstream issue #950 by causing Glance to exit with a nonzero status when the HTTP server fails to start instead of remaining running in a broken state. This allows container restart policies and external monitoring to correctly detect and respond to startup failures.
- Frontend architecture and UX hardening — Establishes explicit browser-side lifecycle, diagnostics, failure-recovery, responsive-behavior, and resource-ownership contracts while preserving existing widget-specific behavior. Frontend diagnostics are centralized, page-content failures and timeouts recover visibly instead of leaving the interface waiting, asynchronous authentication and theme failures are contained, and refreshable components clean up resources that can survive live DOM replacement. Root-local browser initialization shared by initial page rendering and live widget replacement is owned by a common content-root lifecycle, while page-global behaviors retain independent page lifecycle ownership. Page-global search, relative-time, clock, and theme behavior is implemented in focused JavaScript modules, while
page.jsremains the composition boundary for page setup, content-root initialization, live widget replacement, cleanup, and live-update lifecycle ownership. When frontend diagnostics are enabled, browser lifecycle and error reporting is supplemented with page-content, initialization, live-replacement, navigation, resource, DOM, memory, and long-task performance observations that are automatically returned to structured backend logs. A typed backend-to-browser diagnostic command channel uses the existing live-update connection to request explicitly implemented performance snapshots, fixed-duration long-task captures, and browser runtime state without providing arbitrary remote JavaScript execution. Deterministic browser regression coverage protects desktop and mobile navigation and layout, semantic theme behavior, disclosures, live widget replacement, page-load recovery, authentication recovery, and contained frontend failures alongside the existing visual QA system. Native Chromium/V8 coverage can also report named-function execution for Glance-owned JavaScript exercised by the maintained desktop, mobile, and authentication browser scenarios, providing an informational view of frontend execution gaps without treating coverage percentage as a release threshold. - Live widget updates — Addresses upstream issue #1042, with related upstream implementation work in PR #955 and PR #1041, by automatically updating visible widgets in the browser when their server-side refresh completes, without requiring a full page reload. Live updates reuse the existing widget refresh scheduler and cache timing rather than introducing a separate polling cycle. The browser identifies independently replaceable widget targets currently present in its DOM and includes those widget IDs when establishing the Server-Sent Events (SSE) subscription, allowing the server to suppress notifications that cannot affect that browser while preserving the existing unfiltered protocol for compatible clients. The browser fetches and replaces only an affected widget that remains present, preserving surrounding page and container state such as selected group tabs. Nested refreshable widgets are supported where they render independent replacement targets, concurrent notifications are coalesced safely, diagnostic commands remain independent of widget filtering, and browser-side behaviors are reinitialized only within replaced widget content. The feature requires no additional configuration and falls back to existing static page behavior when SSE is unavailable. Runtime reloads prepare the candidate scheduler without activating it until the retiring generation has stopped, so reused widgets have a single refresh owner during handoff rather than competing old/new schedulers. The runtime diagnostics expose bounded live-update broker state including active subscriptions, widget notification publication/subscriber matching/coalescing, diagnostic-command enqueueing, and queue drops.
- Lazy image failure recovery — Handles failed lazy-loaded images as a terminal presentation state and completes their normal transition cleanup, hiding the browser's broken-image indicator while preserving layout space and preventing failed image requests from being repeatedly treated as pending lazy loads.
- Versioned asset base URL fix — Corrects versioned asset paths when Glance is configured with a base URL, ensuring assets such as the web manifest resolve beneath the configured base path instead of producing malformed paths or HTTP 404 responses.
- Static asset error caching — Preserves normal HTTP error semantics for missing static assets by applying cache-control headers only to successful and redirect responses. Missing files therefore return HTTP 404 without receiving success-oriented cache directives that could cause the absence to be retained by browsers or intermediaries.
- Search autofocus fix — Incorporates upstream PR #885, ensuring search widgets configured with
autofocusreliably receive focus after dynamic initialization, including in browsers such as Firefox. - Search direct domain navigation — Adapts upstream PR #1073 by adding an opt-in
open-domainssetting to the Search widget. Domain names and HTTP(S) URLs can be opened directly while bang searches retain precedence, non-domain input continues through the configured search engine, and blocked popup handling avoids dereferencing a missing browser window.
- Structured operational logging and diagnostics — Adds structured lifecycle, failure, recovery, configuration, and runtime diagnostics for improved container and service observability without turning normal refresh activity into log noise. Glance logs meaningful application and lifecycle events, reports the first transition of a widget into a failed or degraded state with an actionable failure classification and sanitized failure cause, and records recovery without repeatedly logging the same continuing failure. Refreshable widgets use a common failure, partial-content, cancellation, retry, degraded-state, stale-content, and recovery lifecycle. An authenticated
/api/diagnosticsendpoint exposes current in-memory operational state including per-widget refresh attempts and outcomes, last success and failure times, refresh duration, active refresh state, consecutive failures, failure classification, sanitized failure cause, refresh-lock skips, scheduler lag, maximum observed scheduler lag, and next scheduled update, together with aggregate refresh state. Configuration diagnostics expose the active configuration path and load time, the latest reload attempt and result, and retain the most recent rejected reload with source file, line, and message where available even after a later successful reload. Invalid reloads leave the currently running application active. The scheduler additionally emits exception-oriented warning and recovery transitions when scheduler lag becomes excessive or refresh-lock contention persists across consecutive scans, while avoiding routine refresh noise and duplicate provider-failure reporting. An authenticated/api/diagnostics/reportendpoint presents the runtime diagnostics as a human-readable operational report, supplemented with application version, source revision, uptime, and bounded retained frontend diagnostic history when browser diagnostics are enabled. Current backend degradation, rejected configuration state, or a requested profiling listener that failed to run marks the report as requiring attention; recovered widget failures and historical frontend problems remain visible without by themselves changing current runtime health. The public/api/healthzendpoint remains a lightweight liveness check independent of provider, widget, configuration, and remote release health, and reports the running version, source revision, and process uptime. HTTP and provider diagnostics are sanitized to avoid exposing configured URLs, query strings, response bodies, authentication credentials, tokens, cookies, and other potentially sensitive values. Browser personal-state parse, server-read, and server-write failures use the same bounded frontend diagnostic channel as other contained browser failures while retaining their existing fallback behavior. Internal template-rendering failures include widget identity in server-side logs while clients receive a generic HTTP 500 response. - Performance diagnostics and regression measurement — Adds an evidence-driven performance investigation layer spanning the Go runtime, backend HTTP handling, shared caches, live-update infrastructure, and browser runtime. Frontend diagnostics can record browser performance snapshots, long tasks, page setup and live-replacement timings, resource and DOM measurements, and backend HTTP request duration in structured server logs. Supported typed diagnostic commands can request performance snapshots, fixed-duration long-task captures, and browser runtime state from connected browsers, with command-correlated results retained in the runtime diagnostics report without exposing arbitrary script execution. When diagnostics are enabled, Go
pprofis exposed on a separate loopback-only127.0.0.1:6060listener rather than through the public Glance router. The authenticated runtime diagnostics report whether that profiling listener was requested and is currently running and retain its most recent failure when applicable; a successful restart clears stale failure state. Repository Makefile targets provide controlled profile capture and summaries. The production-representative performance workflow correlates a browser performance snapshot with backend rendering, refresh, refresh-lock, widget-activity, and outbound HTTP diagnostics from the same isolated runtime, including bounded attribution for the slowest relevant render, refresh-lock wait, and recent widget refresh activity. This allows browser-visible latency to be distinguished from application rendering, synchronization, provider refresh, and external network latency without constructing an ad-hoc test environment. Focused Go benchmarks provide repeatablens/op, allocation, and memory measurements for performance-sensitive shared infrastructure, including keyed-resource-cache scaling and live-update broker publishing and coalescing. Performance changes are therefore evaluated against measured behavior and repeatable regression baselines rather than optimization by assumption.
- Reddit proxy challenge routing — Addresses upstream issue #1016 by ensuring Reddit LOID challenge acquisition uses the same configured proxy route as subsequent Reddit requests. LOID cookies are cached independently per network route so direct requests and distinct proxies do not incorrectly share challenge state, while preserving the existing six-hour cache and request synchronization behavior.
- DNS statistics correctness — Prevents invalid percentage values when DNS providers return zero queries or zero blocked queries. Graph normalization and blocked-domain percentages safely remain at zero when their denominator is zero, covering AdGuard Home, Pi-hole v5, Pi-hole v6, and Technitium DNS Server. AdGuard Home average response times also retain sub-millisecond precision instead of being truncated to zero and incorrectly causing the widget to display the blocked-domain fallback statistic in place of latency.
- RSS parsing and rendering hardening — Improves RSS title and image parsing based on upstream PR #1044 and addresses upstream issue #1011, including HTML title sanitization, image discovery from item metadata and feed content, and safe resolution of relative image URLs. Also addresses upstream issue #919 by removing embedded HTML comments from feed descriptions, and issue #962, with additional fallback coverage informed by PR #1075, by validating and resolving RSS item links before rendering so malformed or unsafe URLs cannot produce Go template
ZgotmplZoutput. Avoids unnecessary RSS image discovery and HTML image parsing for the standard list style while preserving image processing for styles that render thumbnails, adapted from Dynacat commitf7b5c08. - Markets previous-close correctness — Uses Yahoo Finance explicit previous-close data for market percentage-change calculations when available, falls back to the most recent nonzero historical close when necessary, and safely falls back to the current price when no previous close is available. Adapted from Dynacat commit
93a9fab. - GitHub release fetching optimization — Optimizes GitHub release requests for repositories configured with
include-prereleases: trueby requesting only the single release that Glance consumes instead of GitHub's default page of results, reducing response size and processing overhead without changing release selection behavior. Based on Dynacat PR #97. - HTTP connection reuse hardening — Adds a finite idle connection timeout and consistent connection-pool settings to the shared HTTP transports, preventing idle connections from being retained indefinitely. Adapted from
matt2k7/glancecommitb13c1f9. - Transient HTTP I/O failure classification — Classifies EOF and unexpected-EOF failures from provider HTTP operations as transient refresh failures, preserving the existing centralized retry, degraded-state, stale-content, diagnostics, and recovery lifecycle while reporting these failures accurately instead of as unknown provider errors. Informed by the transient-EOF failure case addressed in upstream PR #1084; the fork retains its shared HTTP transport, resource caching, failure classification, and widget-lifecycle retry architecture rather than introducing provider-local Yahoo retry handling.
- Trusted reverse-proxy boundaries — Adds optional
server.trusted-proxiesconfiguration for IP addresses and CIDR ranges of reverse proxies that connect directly to Glance. Withserver.proxied: trueand trusted proxies configured, forwarded client identity and protocol headers are trusted only when the direct TCP peer matches a configured range, preventing untrusted direct clients from spoofing proxy-derived identity or HTTPS state. IPv4, IPv6, and CIDR ranges are supported. Omittingtrusted-proxiespreserves the existingproxied: truebehavior for backward compatibility, while direct TLS remains authoritative for secure-session cookies. - HTTP response security baseline — Applies conservative security headers centrally to Glance responses, including
X-Content-Type-Options: nosniffandReferrer-Policy: strict-origin-when-cross-origin. More restrictive deployment-dependent policies such as CSP, HSTS, and framing restrictions are not imposed globally because they can conflict with user-provided document head content, Custom API templates, extensions, external resources, embedding, or reverse-proxy TLS ownership. - Browser trust and bounded runtime state — Separates externally supplied link targets from administrator-trusted URLs so provider and calendar data cannot bypass Go template unsafe-scheme filtering, requires operator-wide dashboard authorization for active frontend diagnostic commands, bounds per-identity personal-state cardinality and total persisted document size, bounds the Custom API runtime regular-expression cache, normalizes and redacts Reddit proxy route identity while bounding shared LOID route state, marks authenticated dynamic dashboard HTML as private/non-cacheable, and resolves configured trusted-proxy chains from the direct peer toward the first untrusted client hop while retaining legacy proxied behavior when no trusted proxy list is configured.
- Secure local resource proxy — Adds an optional server-side resource proxy for displaying images from explicitly authorized HTTP-only services on an HTTPS Glance dashboard without exposing upstream URLs or embedded credentials to the browser. Operators configure an exact allowlist of HTTP origins; when a Custom API template uses the
proxyURLhelper for an eligible resource, Glance registers the upstream URL behind an opaque application-generation-scoped identifier and serves the image through an authenticated/api/resource-proxy/endpoint. The proxy uses a dedicated transport that does not inherit environment proxy settings, does not forward browser cookies, authorization, or arbitrary request headers, does not relay upstream cookies, revalidates destinations before fetching, and permits redirects only within the originally authorized origin. Responses are bounded in size and restricted to supported raster image content types, while SVG and general-purpose HTML, XML, JSON, JavaScript, CSS, media, PDF, and arbitrary binary content are rejected. Allowed origins require exact normalized scheme, host or IP, and effective-port matching and do not support wildcards, CIDR ranges, user information, paths, queries, or fragments. The feature is disabled when no allowed origins are configured, preserving existing behavior, and operational errors and diagnostics identify proxy failures without logging credential-bearing upstream URLs. The generation-scoped opaque URL registry is bounded with least-recently-used eviction so rotating credential-bearing resource URLs cannot grow process memory without limit. Eligible configured branding/icon and provider-supplied image URLs are automatically routed through the same proxy policy so HTTP-only branding, page, widget, monitor, bookmark, footer, Docker-label, compact Status Bar, RSS, Reddit, Twitch, Videos, and media images do not leak mixed-content requests into HTTPS dashboards. Browser-managed image surfaces render HTTPS and local relative images directly, proxy explicitly allowlisted HTTP origins, and omit non-allowlisted HTTP, protocol-relative, credential-bearing, or unsupported-scheme images rather than intentionally emitting insecure browser requests. - Bounded provider responses — Applies explicit response-body size limits to shared and direct provider HTTP paths so an unexpectedly large or unbounded external response cannot consume arbitrary process memory. Oversized responses produce a classifiable provider failure and participate in the normal degraded, retry, stale-content, diagnostics, and recovery lifecycle rather than being silently truncated or accepted.
- YouTube uploads feed fallback — Falls back from the Shorts-filtered
UULFchannel uploads feed to the standardUUuploads feed when the primary feed fails, while preserving existing cache and error behavior. Adapted fromJacksonMcDonaldDev/glancecommitb6082e3. - Remote Server Stats mountpoint configuration — Applies mountpoint visibility, naming, and ordering settings to system information returned by remote Glance agents. Adapted from
rakkateichou/glancecommit64d3b1c. - Server Stats configurable mountpoint ordering — Adds optional
mountpoint-orderconfiguration for local and remote Server Stats entries, supportingusage,name, andpathordering while preserving usage-descending order as the default. The selected order consistently drives the disk headline, combined progress display, and mountpoint popover. Inspired by Dynacat issue #159. - Partial provider failure visibility — Preserves usable data while surfacing degraded provider results that were previously easy to lose. Local Server Stats retains successfully collected host information when another local collection step fails and reports the refresh as partial, while Lobsters skips entries with malformed timestamps and reports partial content when valid entries remain. Complete source failure continues to use the existing no-content behavior.
-
Popover viewport containment — Clamps shared popover positioning to the visible viewport after above/below placement and gives oversized popover content an internal vertical scroll region so content remains reachable when neither side can contain it. Adapted and extended from
Gloweet/glancecommit0e12085. -
Server Stats dynamic multi-drive display — Renders progress values for every configured or discovered mountpoint instead of limiting the visible combined disk bar to the first two mountpoints, matching the existing backend and popover support for arbitrary mountpoint counts. Adapted from the presentation portion of
ToTt0G/glancecommitc5d6059; its separate host-root remapping changes are intentionally not incorporated. -
ChangeDetection internal/external URL separation and page-title fallback — Adds optional
link-urlconfiguration so Glance can use an internal ChangeDetection API address while generating browser-facing links from a public address, defaulting toinstance-urlfor compatibility. Watch titles now fall back from explicittitleto ChangeDetectionpage_titlebefore deriving a title from the URL. Adapted fromjuvanj/glancecommitbbe1b6dandkirolos-esmat/glancecommit9b580fe. -
Custom API numeric conversion compatibility — Extends
toInt,toFloat, and decorated JSON numeric accessors to handle numeric strings, percentage strings, native numeric values, and GJSON values consistently while preserving truncation for integer conversion. Adapted fromToTt0G/glancecommit19ad8e5and follow-up408b160. -
Twitch Channels persisted-query recovery — Updates the Twitch
StreamMetadatapersisted query after Twitch invalidated the previous hash and preserves Twitch GraphQL error messages so failures such asPersistedQueryNotFoundremain diagnosable instead of surfacing as secondary JSON errors. Adapted fromGloweet/glancecommita143edb. -
Docker category filtering for parent/child groups — Incorporates upstream PR #1080, applying Docker container category filtering to top-level containers rather than filtering children independently. Children associated through
glance.parentremain grouped with a matching parent regardless of whether the child has no category or a different category, while hidden-container behavior remains unchanged. -
Mountpoint CLI fix — Incorporates upstream PR #1065, fixing the
mountpoint:info <path>command so it can be invoked as documented instead of being rejected as an unknown command. -
Mountpoint auto-detection fix — Incorporates upstream PR #1070, addressing upstream issue #1074 by fixing automatic mountpoint discovery in plain containers to include Docker
overlayfilesystems while filtering out virtual filesystems such as proc, sysfs, tmpfs, and cgroups. -
IPv6 Docker remote sources — Incorporates upstream PR #1064, correctly formatting IPv6 addresses used by remote Docker sources while preserving TCP, HTTP, HTTPS, explicit-port, and default-port behavior.
-
YAML comment variable parsing — Incorporates upstream PR #965, preventing configuration variables inside YAML comments from being expanded while correctly preserving hashes inside quoted values and handling escaped or doubled quotes.
The fork includes substantially expanded automated regression coverage intended both to protect fork-specific behavior and to make future upstream synchronization safer.
Regression coverage includes configuration parsing, reload behavior, and runtime diagnostics; configuration watcher concurrency and shutdown; application and HTTP server lifecycle behavior; dashboard routing; widget refresh synchronization, telemetry, recovery, caching, cancellation, scheduler lag, and lock contention; healthy, failed, partially available, degraded, stale, canceled, and recovered transitions; retained configuration-reload rejection diagnostics; Custom API requests, templates, Sprout helper compatibility and error propagation, timeouts, stale fallback, compact Status Bar refresh failure and recovery behavior, and errors; Server Stats partial-source and cancellation behavior; Docker and provider behavior; malformed or incomplete external responses; transport failures; diagnostic sanitization; HTTP error boundaries; DNS zero-value calculations and AdGuard sub-millisecond latency rendering; application initialization and migration; and regression tests for defects discovered while stabilizing the fork.
The test suite contains hundreds of tests across application behavior, providers, lifecycle boundaries, frontend behavior, and regression cases. Coverage is measured continuously as engineering evidence rather than treated as a goal by itself or a fixed release threshold. Testing is concentrated on behavior where regressions, malformed external data, concurrency, lifecycle transitions, provider failures, and upstream changes present meaningful risk.
Concurrency-sensitive behavior is validated with Go's race detector. During stabilization, important suites were also executed repeatedly with both normal and race-enabled test runs to expose intermittent concurrency or lifecycle failures.
Goroutine lifecycle regression protection additionally uses go.uber.org/goleak to detect unexpected background work that survives test completion. Package-wide leak verification complements rather than replaces the race detector and existing scheduler and failure/recovery soak tests: the race detector identifies unsafe concurrent memory access, soak tests detect workload-driven goroutine growth, and goleak identifies goroutines that outlive their intended ownership boundary. Targeted leak assertions cover high-risk lifecycle paths including scheduler cancellation, application runtime shutdown, configuration-generation replacement, live-update termination, shared keyed-resource and RSS fetch completion after caller cancellation, graceful HTTP server shutdown, and profiling-listener reconciliation. The package-wide check explicitly closes idle connections owned by the process-global shared HTTP transports before final leak verification so normal connection pooling is not misclassified as leaked application work.
Native Go fuzzing provides an additional regression boundary for parsers, codecs, and security-sensitive normalization or policy logic where malformed or unexpected inputs present meaningful risk. Maintained fuzz targets cover OIDC principal decoding, V4 session-token verification, resource-proxy origin normalization and allowlist enforcement, RSS URL resolution, and YAML comment scanning. Fuzzing complements deterministic tests, the race detector, goleak, and soak testing rather than replacing them. Focused fuzzing is available through make fuzz FUZZ=FuzzName, while make fuzz-all runs the maintained targets sequentially with a bounded per-target duration. Active fuzzing is intentionally not part of the deterministic make check or make validate release gates; ordinary Go test execution still runs each fuzz target's seed corpus as regression coverage. When fuzzing discovers a production defect, the minimized failure is converted into a deterministic regression case so protection does not depend on a local fuzz cache. The initial fuzzing pass identified and permanently covered inconsistent OIDC principal-length validation and malformed RSS authorities produced during relative URL resolution.
Several production defects were discovered through this process, reproduced with regression tests, and then fixed. Those tests remain in the suite to protect against recurrence.
Development follows a two-branch integration and release model:
development branch → dev → main → formal release → production deployment → main-to-dev synchronization
The long-lived dev branch is the integration branch for ongoing development. Focused feature, fix, refactor, and documentation branches are created from a clean local dev branch and merged back into dev through pull requests. Local dev may intentionally contain committed work that has not yet been pushed when that work is being parked for inclusion in the next feature pull request. In that state, origin/dev must remain an ancestor of local dev; behind or diverged histories are not accepted for new branch creation.
The long-lived main branch is the stable, release-ready branch. Changes reach main only through a controlled promotion pull request from dev. Direct development on either dev or main is intentionally avoided.
Both dev and main are protected branches. Pull requests targeting either branch are automatically validated through the repository make check contract, keeping CI aligned with local pre-pull-request validation rather than maintaining a separate duplicated validation list.
The repository Makefile provides standardized commands for development, validation, repository inspection, GitHub pull request operations, CI monitoring, release management, and production deployment.
Common targets include:
make test
make test-race
make test-count COUNT=10
make test-race-count COUNT=10
make fuzz FUZZ=FuzzVerifySessionTokenV4 FUZZTIME=30s
make fuzz-all FUZZTIME=10s
make build
make test-instance-fixture-start
make test-instance-fixture-stop
make test-instance-start
make test-instance-status
make test-instance-stop
make frontend-audit
make frontend-check
make frontend-coverage
make visual-check
make visual-screenshots
make visual-docs
make visual-docs-promote
make visual-all
make visual-final
make test-prod-start
make test-prod-status
make test-prod-stop
make test-container-start TEST_RUNTIME_CONTAINER=<container>
make test-container-status
make test-container-stop
make test-all-stop
make fmt-check
make diff-check
make staged-check
make lint
make check
make validate
make validate-all
make lighthouse
make coverage
make benchmark
make pprof-capture
make pprof-summary
make vuln
make status
make staged-diff
make upstream-status
make verify-dev
make verify-main
make branch NEW_BRANCH=feature/example
make park
make ship TITLE='...' BODY_FILE=<file>
make ship-nonruntime TITLE='...' BODY_FILE=<file>
make push
make pr-create TITLE='...' BODY_FILE=<file>
make promote-create TITLE='...' BODY_FILE=<file>
make pr-view PR=<number>
make pr-runs
make pr-merge PR=<number>
make post-merge PR=<number>
make pr-finish PR=<number>
make promote-finish PR=<number>
make sync-finish PR=<number>
make workflow-status
make image-runs
make ci-watch RUN=<id>
make ci-view RUN=<id>
make release-status
make release-check
make release
make release-finish
make deploy-status
make deploy
make deploy-finish
make branch creates normal development branches from a clean dev branch. When local dev exactly matches origin/dev, branch creation proceeds normally. When local dev is strictly ahead and origin/dev is its ancestor, the target reports the committed parked work and intentionally carries those commits into the new feature branch. Branch creation refuses local dev histories that are behind or have diverged from origin/dev. make pr-create creates the normal feature-to-dev pull request and intentionally refuses to operate from either long-lived branch. make promote-create is the explicit path for creating a dev-to-main promotion pull request.
make post-merge determines the merged pull request's base branch automatically. After a normal feature merge it updates and leaves the repository on dev; after a promotion merge it updates and leaves the repository on main. Ordinary updates remain fast-forward-only. When parked local dev commits were carried by a merged feature pull request and therefore make the old local dev history non-fast-forwardable to the resulting remote merge commit, the target reconciles local dev only after verifying that the merged feature revision is contained in origin/dev and that the old local dev history is contained in that feature revision. Long-lived branches are preserved while merged local feature branches are cleaned up.
The Makefile provides high-level workflows for normal operation while retaining the individual lifecycle targets for inspection and recovery. make ship is the normal end-to-end workflow for runtime and code changes: it stops Makefile-managed development and test runtimes, integrates the feature through dev, promotes dev to main, creates and verifies the formal release, deploys and verifies production, synchronizes main back to dev, performs final workflow verification, and again stops managed development and test runtimes. When BODY_FILE is supplied to make ship, it is treated as a consumable workflow input: it is retained if the workflow fails and removed only after the complete workflow succeeds. make ship-nonruntime is the guarded high-level alternative for qualifying non-runtime changes and does not create a formal release or deploy production.
The lower-level composite workflow targets remain available as recovery primitives. If a high-level workflow stops, make workflow-status should be used first to establish repository, release, CI, image, and deployment state before selecting the appropriate resume target. make pr-finish validates a feature-to-dev pull request, watches its exact-head CI run, merges it, performs post-merge cleanup, and watches publication of the resulting dev image. make promote-finish performs the corresponding guarded dev-to-main promotion through validation, merge, cleanup, and stable-branch verification. make sync-finish handles the post-release main-to-dev synchronization and resulting dev image. make workflow-status provides a combined view of repository relationships, release state, recent CI and image activity, and deployment state.
make release-finish remains the guarded formal-release stage for main: it performs release validation and tag creation, watches the formal release workflow, and reports release and deployment status. When invoked by itself it intentionally does not deploy production. make deploy remains the guarded production-deployment primitive, while make deploy-finish is the recovery/resume stage that deploys an already released main, synchronizes main back to dev, and performs final verification. The high-level make ship workflow intentionally composes these guarded stages and is therefore the explicit end-to-end path that crosses the production boundary.
make check runs the standard fast local pre-pull-request validation suite, including tests, race detection, build, formatting and whitespace checks, documentation contracts, correctness-oriented Go static analysis through make lint, and frontend architecture auditing through make frontend-audit, which enforces semantic theme and frontend diagnostic ownership contracts. The lint policy uses a pinned golangci-lint release and deliberately emphasizes correctness-oriented analyzers rather than style-only churn.
make validate is the authoritative comprehensive release-gate validation and extends make check with deterministic browser regression testing through make frontend-check, visual QA contract validation through make visual-check, and Go vulnerability analysis through make vuln.
make validate-all extends that release gate with informational Go coverage, frontend execution coverage, benchmarks, and Lighthouse analysis for deeper engineering analysis. Those measurements and Lighthouse scores do not become release thresholds merely by participating in the aggregate target.
make lighthouse can also be run independently against the deterministic test instance. It reports Lighthouse category scores and accessibility findings for engineering visibility, uses the maintained Chrome/test-instance infrastructure, and cleans up its temporary report and test runtime when complete.
Deterministic browser regression testing validates page recovery, desktop and mobile behavior, theme interaction, live replacement, disclosures, contained frontend failures, and authentication recovery against an isolated test instance. make frontend-coverage executes those same maintained browser scenarios with native Chromium/V8 coverage enabled and reports named-function execution for Glance-owned JavaScript. Modules not loaded by those scenarios are reported separately rather than being included in the execution denominator. The result is informational coverage for identifying meaningful frontend test gaps; it is not line, statement, or branch coverage and does not enforce a percentage threshold. Repeated test targets are available for concurrency-sensitive or high-risk changes where a single successful test execution may not provide sufficient confidence.
For interactive development and browser validation, make test-instance-start builds the current source tree and starts an isolated Glance instance on port 18080 using test-instance.yml. The test configuration is a maintained regression and visual fixture rather than a disposable minimal configuration. It exercises all registered widget types, hierarchical widget defaults and overrides, built-in and configured themes, semantic presentation components, layout composition, and deterministic content needed for browser validation. make test-instance-status reports both process and HTTP health, while make test-instance-stop stops the isolated environment and removes runtime artifacts while preserving the maintained test configuration.
The test-instance lifecycle also owns a deterministic local fixture API used by visual and Extension testing. make test-instance-fixture-start starts the fixture server on port 18089, verifies its health, and records its process and log state; make test-instance-fixture-stop removes that runtime state. Starting the test instance automatically starts the fixture first, startup failures clean up the fixture, status reports both services, and stopping the test instance stops both. The fixture server is therefore infrastructure owned by the Makefile lifecycle rather than by individual screenshot scripts.
The repository also maintains a canonical visual QA system under testdata/visual. Every registered widget is classified in the visual gallery and mapped to an isolated canonical screenshot. Dedicated fixture pages cover widget families, themes, composition, and documentation examples. make visual-check validates registry completeness, widget screenshot coverage, visual-page configuration, and documentation-image ownership. make visual-screenshots captures the canonical desktop QA set, currently consisting of 14 full-page screenshots and 37 isolated widget screenshots. make visual-screenshots VIEWPORT=mobile captures the page set at the maintained 430x900 mobile viewport without replacing the canonical desktop artifacts. The screenshot and documentation workflows also support DASHBOARD=<slug> or PAGE=<slug> for focused development runs. Selectors are validated and mutually exclusive, and focused runs preserve artifacts outside the selected scope while unqualified commands retain complete release-validation behavior.
Documentation screenshots use the same deterministic browser fixtures instead of being maintained as unrelated hand-created images. Browser-managed documentation images live in stable docs/images/widgets, docs/images/pages, and docs/images/themes namespaces, while instruction images that cannot be generated from the Glance fixture remain statically managed under docs/images/instructions. make visual-docs generates browser-managed documentation images into staging, make visual-docs-promote promotes the generated set into the documentation tree, and the visual contract verifies that every referenced documentation image exists and that no unmanaged image remains in the managed namespace. make visual-all captures canonical visual QA and stages browser-managed documentation images in one browser run. make visual-final is the normal finalization workflow: it performs that single aggregate capture, promotes the resulting staged documentation images, and verifies the final visual contract without recapturing the same screenshots through separate component targets. This keeps widget documentation, theme examples, screenshots, and the actual current UI synchronized as the presentation system evolves.
Production-runtime browser validation uses the same isolated port 18080 while preserving the running production container. The test-prod-start target builds the current source tree into a local test image carrying the current source revision and starts it using TEST_RUNTIME_CONTAINER as its runtime reference. This provides pre-commit validation of current local changes against the real production environment, configuration, assets, bind mounts, Docker networks, environment, and sysctls. TEST_FRONTEND_DIAGNOSTICS=true creates an isolated temporary copy of the production configuration with frontend diagnostics enabled, leaving the real production configuration unchanged; this supports production-representative browser telemetry, backend HTTP timing, typed diagnostic commands, and loopback-only Go profiling before a change is committed. The test-prod-status target reports container and HTTP status, while test-prod-stop removes the isolated container, temporary local image, and standard temporary diagnostic configuration.
Performance investigation is supported by make benchmark, which executes the maintained Go benchmark suite with memory and allocation reporting, and by make pprof-capture and make pprof-summary for controlled Go profile collection and inspection against a diagnostics-enabled runtime. These tools complement make frontend-check and make frontend-coverage: benchmarks and profiles measure backend/runtime behavior, while frontend diagnostics provide browser and end-to-end timing evidence. They are diagnostic and regression-measurement tools rather than additional release gates unless a particular change requires their evidence.
Reliability and performance regression coverage also includes controlled scheduler and failure/recovery soak tests, a provider failure-contract matrix covering cancellation, deadlines, network timeouts, authentication and authorization failures, request failures, rate limiting, server failures, malformed JSON and XML, oversized responses, partial content, and successful recovery, plus Custom API regular-expression cache benchmarks. Refresh fanout is benchmarked through the real scheduler path at 1, 10, 50, 100, and 175 simultaneously due widgets. The maintained 175-widget benchmark remains well below one millisecond per dispatch cycle with about 17 KB allocated, providing evidence that the existing bounded-concurrency scheduler remains appropriate at the fork's current production scale. Regular-expression measurements likewise provide a baseline for cached and continuously changing patterns; no cache-eviction mechanism is introduced without evidence that real template workloads require one.
After changes have integrated into dev, test-container-start validates the published ghcr.io/samcro1967/glance:dev artifact against the same real runtime configuration. It verifies the successful development-image workflow for the current origin/dev revision, pulls the development image, starts an isolated container on port 18080, and verifies the expected image and revision. test-container-status reports container and HTTP status, while test-container-stop removes the isolated container while preserving the pulled image.
The canonical source test, local production-runtime test, and published-development-image test intentionally share port 18080 and are used mutually exclusively. Together they provide deterministic fixture validation, pre-commit validation against the real dashboard, and post-integration validation of the exact published development artifact.
make test-all-stop is the aggregate cleanup target for all Makefile-managed development and test runtimes. It delegates to the existing source-test, production-runtime-test, and published-development-image stop targets rather than duplicating their cleanup logic, preserving each lifecycle's ownership semantics. The aggregate target is safe to run when one or more managed runtimes are already absent.
The fork includes additional security and dependency maintenance beyond functional changes.
- Go and project dependencies are periodically reviewed and updated.
- GitHub Actions dependencies are maintained alongside application dependencies.
govulncheckis used to identify reachable Go vulnerabilities.- Correctness-oriented Go static analysis is performed through a pinned golangci-lint configuration as part of the standard repository validation contract.
- Container builds upgrade available Alpine packages during the image build so published images receive current package-level security fixes available from the configured Alpine repositories.
- Operational and provider diagnostics are intentionally sanitized to avoid logging authentication credentials, authorization headers, cookies, tokens, configured URLs containing sensitive query parameters, response bodies, or similar potentially sensitive information.
- Forwarded client identity and protocol headers can be restricted to explicitly trusted reverse-proxy addresses and networks, preventing untrusted direct peers from asserting proxy-derived request identity or HTTPS state.
- Glance applies a centralized conservative HTTP response security-header baseline while leaving deployment-specific TLS, framing, content-security, and external-resource policies under operator control.
- Error responses exposed to HTTP clients avoid disclosing internal template-rendering details while retaining actionable server-side diagnostics.
Security scanning can still report vulnerabilities for which an upstream package or distribution fix is not yet available. The presence of such a report does not imply that the fork contains a project-level fix for the underlying third-party vulnerability.
Container images for this fork are published exclusively to GitHub Container Registry.
The development image is:
ghcr.io/samcro1967/glance:dev
This mutable tag represents the current integrated dev branch. A successful push to the protected dev branch automatically builds and publishes this image. Feature branches do not publish container images, and promotion of dev to main does not by itself publish or move a container tag.
Formal releases publish:
ghcr.io/samcro1967/glance:v<upstream-version>-samcro1967.r<revision>
ghcr.io/samcro1967/glance:latest
For example:
ghcr.io/samcro1967/glance:v0.8.5-samcro1967.r001
ghcr.io/samcro1967/glance:latest
The versioned tag is the immutable identity of a formal fork release. latest identifies the most recent formal fork release and points to the same released image. It is not a development or branch-build tag.
Formal release images are built by GoReleaser for Linux AMD64 and ARM64 and published as multi-architecture manifests. Architecture-specific image tags are used internally to construct those manifests. Formal releases of this fork do not publish standalone binary archives; users requiring a standalone executable can build the fork from source.
Published images contain OCI revision metadata identifying the source commit from which the image was built.
The resulting image lifecycle is:
development branch → dev → ghcr.io/samcro1967/glance:dev
dev → main
└─ no image publication
main → formal release tag
├─ ghcr.io/samcro1967/glance:v<version>-samcro1967.r<revision>
└─ ghcr.io/samcro1967/glance:latest
formal release → guarded production deployment
main → dev synchronization
└─ restores the post-release long-lived branch relationship
The repository includes Makefile-based deployment tooling intended to make deployments reproducible and to ensure that production receives only a formal fork release.
make deploy-status performs a read-only comparison of the current source branch and revision, the locally available ghcr.io/samcro1967/glance:latest image and its source revision, and the currently running production container and its source revision.
make deploy performs a guarded production deployment. Before changing the running service it:
- requires deployment from
main; - requires a clean source working tree;
- refreshes
originand requires localmainto exactly matchorigin/main; - pulls
ghcr.io/samcro1967/glance:latest; - reads the image's OCI source revision;
- requires the released image revision to exactly match the source repository's current
mainrevision; and - refuses to recreate the production service if those revisions differ.
After the image passes validation, the deployment recreates only the Glance Compose service and verifies that the running container reports the expected source revision, uses the exact validated image, the local Glance HTTP endpoint becomes ready, and recent container logs are available for immediate inspection.
Because latest moves only when a formal release is created, this revision check also prevents an unreleased main revision from being deployed. If main has advanced beyond the most recent formal release, production deployment remains blocked until that revision has completed the formal release process.
The fork continues to track the upstream Glance repository while treating upstream compatibility as an explicit architectural constraint rather than requiring the fork's internal implementation to remain identical to upstream.
Existing upstream Glance configurations are intended to continue working without migration. Fork-specific configuration is generally optional and additive, and existing behavior is preserved when new functionality is omitted unless a documented correctness or reliability change intentionally alters it.
Upstream changes are reviewed before integration rather than being automatically applied to production. The expanded regression, race-detector, browser, visual, static-analysis, and vulnerability-validation infrastructure makes it easier to evaluate future upstream changes while protecting fork-specific functionality, architectural contracts, and previously fixed defects.
Where functionality in this fork originates from an existing upstream pull request or another Glance-derived project, the corresponding source is identified in this document. Other changes were developed specifically for this fork based on functionality or reliability requirements encountered while operating it.
Upstream issues, discussions, and pull requests relevant to fork implementations are referenced within this repository for provenance and traceability.
The fork intentionally avoids unnecessary divergence from upstream. Production changes are made when they provide required functionality, address an observed defect, improve operational reliability or maintainability, establish a useful shared architectural contract, or provide meaningful regression protection. Areas that are functioning correctly are generally left unchanged rather than modified solely to increase test coverage or introduce speculative abstractions.
This allows the implementation to evolve substantially where justified without unnecessarily creating a configuration or user-experience boundary between upstream Glance and this distribution.
The fork has undergone a focused stabilization and architectural consolidation effort covering configuration handling, application lifecycle behavior, widget refresh and recovery, provider failure handling, HTTP infrastructure, frontend lifecycle ownership, live updates, concurrency, shutdown and reload behavior, diagnostics, security, regression testing, CI validation, and production deployment.
Core architecture has been consolidated around explicit ownership boundaries while preserving existing behavior. Configuration compilation owns ordinary configuration validation and routing normalization before application construction; widget construction and type-specific capability metadata share a single explicit registry; equivalent keyed provider resources use shared cache, request-coalescing, generation-independent shared-fetch ownership, caller cancellation, and idle-retention mechanics while resources with different semantics remain independent; Calendar and ICS Events share common ICS source-default and event-ordering mechanics while retaining widget-specific behavior; refreshable widgets share common failure, degraded, partial-content, cancellation, retry, stale-content, recovery, and committed-render-snapshot semantics; and browser initialization distinguishes content-root lifecycle ownership from page-global lifecycle ownership so live replacement does not create parallel frontend implementations.
The stabilization process included targeted race-detector testing and repeated execution of concurrency-sensitive tests. Multiple defects discovered during this work were first reproduced through regression tests and then corrected, leaving those tests in place to protect against recurrence.
The codebase is now treated as a production baseline rather than an active stabilization project. Runtime failures and degraded states use a common lifecycle contract, exception-oriented logging surfaces actionable state transitions without routine refresh noise, authenticated in-memory diagnostics provide current refresh, scheduler, and configuration-reload state for operational investigation, correctness-oriented static analysis provides another pre-integration defect boundary, and deterministic browser, visual, frontend-coverage, and Lighthouse tooling provide additional evidence about user-facing behavior.
Future changes are expected to focus on required functionality, observed production defects, worthwhile upstream changes, dependency and security maintenance, maintainability improvements supported by concrete evidence, and regression protection for newly discovered issues.
The intent is to keep the fork maintainable, transparent, upstream-compatible, and operationally dependable while allowing its internal architecture to evolve where doing so provides demonstrated value.
See the configuration documentation for details on using the additional widgets and functionality.