What's changed
A big usability round for the alert view — saved filters, a Pin & Hide label display, settings that follow your account, and a calmer header and card layout — plus a batch of history-database correctness fixes, most of them for PostgreSQL multi-replica setups.
Breaking Changes
- Jarvis: No breaking changes. Existing
?matchers=links keep working and are rewritten to the new?filter=syntax, and a previously configured default filter is migrated into a saved filter named "Default". - Helm chart 2.0.0: Two stricter render checks turn setups that used to deploy broken into a clear
helm install/helm upgradeerror. (1) SQLite withreplicaCount > 1orautoscaling.enablednow fails regardless ofpersistence.enabled— every pod would otherwise poll Alertmanager on its own and keep a divergent history. Migration: setreplicaCount: 1or switch to PostgreSQL (see docs/persistence.md). (2)auth.providerother thannonenow requiresauth.secretKeyorauth.existingSecret, andauth.provider: oidcadditionally requiresauth.oidc.issuer,auth.oidc.clientIdandauth.oidc.redirectUrl— such releases previously rendered, but the pod never started. Migration: set the missing values. Details in the chart changelog.
Watch the highlights
A two-minute tour of saved filters, Pin & Hide labels, toolbar grouping, the multi-column card grid and one-click claims.
Added
- Saved filters. A new menu in the alert toolbar saves the current matcher chips under a name — apply, rename, overwrite or delete them later, and star one as the default that is applied when you open Jarvis without a filter in the URL. It replaces the old "Default Filter" section in Settings.
- Alertmanager-style filter URLs. Filters are now written to the URL in the matcher syntax you already know from Alertmanager, e.g.
?filter={severity="critical",namespace=~"prod-.*"}. That's about 2.5× shorter than before, so long filters no longer run into proxy request-line limits. - Pin & Hide label display. Settings → Labels is now a single list: pin a label to show it first (in your order), hide it into a "+N" chip, or leave it as is — with "Hide all" / "Show all" and a fixed 8-color palette that reads well in light and dark theme. The "+N" chip opens hidden labels in a popover, so revealing them no longer shifts cards between columns. Hidden labels stay fully filterable and visible in the detail panel. Proposed in #189 — thanks to @daBo-sh for the detailed proposal!
- Settings follow your account. When you're signed in, your preferences are stored on the server and follow you across browsers and devices. Without a login they stay in the browser as before, and logging out never wipes a device's own settings.
- Grouping right from the toolbar. The "Grouped" control now opens a popover to switch grouping on or off and pick the label to group by (searchable, with per-label counts) — no detour through Settings anymore.
- Multi-column card grid. Cards flow into columns balanced by their real height, a section with only a few groups uses the full width, and groups are sorted by most recently fired instead of alphabetically. A new "Card columns" slider in Settings → Display lets you pin the column count (Auto or 1–6).
- Redesigned header. Settings, theme toggle and login/logout/admin live in one always-present user menu with an initials avatar; cluster status, refresh and info open on hover and dock directly under the header.
- One-click claims. Claiming an alert no longer opens a form — it's claimed immediately under your name, and a "+ Note" link lets you add a note afterwards if you want one.
Fixed
- Claims flickering on multi-replica PostgreSQL. Claiming or releasing an alert showed the change for a moment, then lost it until the next poll whenever the follow-up request landed on another pod. Every pod now applies the claim immediately.
- Resolved alerts lost their summary and description. Resolved events were stored without annotations, so the Resolved tab (and the resolved list after a restart) showed alerts without their text. Alerts resolved from now on keep their annotations.
- Occurrence count stuck at 1 for alerts that re-fire in a different cluster than the one they were first seen in. The count now increases no matter which cluster the alert fires in.
- Poll loop could stall for good on PostgreSQL when another pod held the lock for an alert. History writes now give up after a bounded time (10 s lock wait, 30 s overall), so polling keeps going.
- Duplicate "resolved" entries during a leader failover. Recording a resolve is now transactional and locked per alert, just like firing events already were.
- Pods crashing during rolling deploys with PostgreSQL (
duplicate key value violates unique constraint "pg_type_typname_nsp_index") when several pods ran the schema migration at once. Migrations are now serialized. - Unpredictable "last event" when two history entries share a timestamp (common on SQLite), which could throw off grace-period and claim-release decisions.
- Helm chart: auth secret key missing with
database.existingSecret. Using an existing Secret for the database DSN no longer suppresses the generated auth secret key, which left the pod stuck inCreateContainerConfigError. - Smaller UI fixes: a duplicate tooltip and missing pointer cursor on label chips, links in alert descriptions now use the accent color, the claim-note field has a visible border again, and locked filter chips no longer point to a Settings gear that no longer exists.
Changed
- Calmer alert cards and list rows. Alerts inside a group lead with the labels that set them apart, group-wide labels are muted, summaries and descriptions are clamped for even row heights, and list-row actions are consolidated into a single silence menu. Claims show as a quiet blue line; claiming and releasing moved to the detail panel. Label chips have one fixed size with the full value on hover, and never render in alarm red.
- Settings link state. Opening Settings adds
settings=opento the URL, so a reload or back/forward keeps the sheet open. - Dependency updates:
pgx/v55.11.0,golang.org/x/crypto0.57.0, plus frontend and GitHub Actions minor/patch updates.
Full diff: v1.11.0...v1.12.0
Container image
docker pull ghcr.io/kj187/jarvis:1.12.0Digest: sha256:9d9a8bf59f4e3994887a36c1811396b616dd79498e9a2628c9ef1077dc1b9c74
Verify image signature (cosign)
cosign verify ghcr.io/kj187/jarvis@sha256:9d9a8bf59f4e3994887a36c1811396b616dd79498e9a2628c9ef1077dc1b9c74 \
--certificate-identity-regexp="https://github.com/kj187/jarvis/.*" \
--certificate-oidc-issuer="https://token.actions.githubusercontent.com"Verify build provenance (GitHub attestation)
gh attestation verify oci://ghcr.io/kj187/jarvis:1.12.0 --repo kj187/jarvisHelm chart
helm install jarvis oci://ghcr.io/kj187/charts/jarvis --version 2.0.0Chart changes and breaking changes: charts/jarvis/CHANGELOG.md
Verify chart signature (cosign)
cosign verify ghcr.io/kj187/charts/jarvis:2.0.0 \
--certificate-identity-regexp="https://github.com/kj187/jarvis/.*" \
--certificate-oidc-issuer="https://token.actions.githubusercontent.com"SBOM
The SPDX SBOM is attached to this release (sbom.spdx.json) together with its keyless signature bundle (sbom.spdx.json.sigstore.json), and also embedded in the image manifest (docker buildx imagetools inspect).
cosign verify-blob sbom.spdx.json \
--bundle sbom.spdx.json.sigstore.json \
--certificate-identity-regexp="https://github.com/kj187/jarvis/.*" \
--certificate-oidc-issuer="https://token.actions.githubusercontent.com"