Skip to content

Releases: msitarzewski/brew-browser

Brew Browser 0.7.2 / native 0.3.2

Choose a tag to compare

@msitarzewski msitarzewski released this 20 Jul 04:02
a872efc

brew-browser 0.7.2 / Brew Browser native 0.3.2

A bug-fix patch. Signed + notarized; Tauri is the macOS 13+ / Linux build,
native is the macOS 26 SwiftUI build. Split-track versions track the same batch
(native 0.3.2 ≙ Tauri 0.7.2).

Fixes

Homebrew 6.0+ compatibility for vulnerability scanning

The headline fix. In Homebrew 6.0+, the vulns subcommand moved into core and
the standalone homebrew/brew-vulns tap/formula was deprecated and deleted. As
a result, on current Homebrew the vulnerability-scan feature was effectively
broken: detection failed and the "Install brew-vulns" button chased a
formula that no longer exists. Now:

  • Detection falls back to brew help vulns (the built-in subcommand) when the
    legacy prefix check fails — both shells.
  • The install/remediation command is brew update (which is how you get the
    now-built-in subcommand) instead of installing a deleted formula.
  • Formula-name validation accepts 2-segment tap-qualified names (user/name)
    in addition to user/repo/name, while still rejecting shell metacharacters
    and path traversal.

Thanks to @fallenmaverick (#152).

No more startup macOS Keychain prompts

The app read GitHub credential status eagerly on launch, which could trigger a
macOS Keychain access prompt for users who'd never signed in. Both shells now
gate that startup read behind a persisted "has signed in before" flag
(localStorage on Tauri via #152, UserDefaults on native via #155), so a user
who never touches GitHub sees no Keychain prompt on launch.

"59 minutes ago" scan time (WebKit)

Under WebKit, parsing the backend's nanosecond-precision ISO timestamps could
mis-parse the timezone and show a fresh scan as "59 minutes ago" / "1 hour ago".
Timestamps are now truncated to millisecond precision before parsing (#152).

Homebrew subprocess environment

  • Native VulnsService subprocesses now inherit the same Homebrew environment
    ($HOME, analytics-off flags) as the rest of the app, so brew runs
    correctly under the launchd GUI-app context (#152).
  • The Tauri backend prepends Homebrew bin paths to PATH for spawned commands,
    now including Linuxbrew (/home/linuxbrew/.linuxbrew/{bin,sbin}) alongside
    macOS /opt/homebrew + /usr/local (#152, #155).

Acknowledgments

  • @fallenmaverick — the Homebrew 6.0+ vuln compatibility, startup Keychain
    prompt, WebKit date-parsing, and Swift subprocess-env fixes (#152).

Issues & feedback

github.com/msitarzewski/brew-browser/issues.
Every error toast in the app has a "Report" button that pre-fills the issue with
your context.

Brew Browser 0.7.1 / native 0.3.1

Choose a tag to compare

@msitarzewski msitarzewski released this 15 Jul 14:52
9cbd8f0

brew-browser 0.7.1 / Brew Browser native 0.3.1

A small follow-up to 0.7.0 (Bundles). Signed + notarized; Tauri is the macOS
13+ / Linux build, native is the macOS 26 SwiftUI build. Split-track versions
track the same batch (native 0.3.1 ≙ Tauri 0.7.1).

What's new

Resizable Activity console

The bottom Activity console — the live brew output drawer — is now
resizable in both shells, so you can give a long install or upgrade as much
room as you want. Drag the divider to resize; the height persists across
launches (localStorage on Tauri, UserDefaults on native), clamped to a sensible
floor and 60% of the window. A community contribution by @cseelye (#136).

Fixes

  • Linux CI produces artifacts again. The Linux bundle workflow was failing
    at the updater-signing step (it tried to sign an updater artifact with a
    private key CI doesn't hold), so no .deb / .rpm / .AppImage were
    published on tagged releases. The Linux auto-updater is unwired anyway, so the
    build now skips that artifact and uploads the installers as intended (#149).

Note

The resizable Activity console was listed in the 0.7.0 notes but did not make
the 0.7.0 build — it landed just after. It ships here in 0.7.1.

Acknowledgments

  • @cseelye — the resizable Activity console, contributed to both shells
    (#136).

Issues & feedback

github.com/msitarzewski/brew-browser/issues.
Every error toast in the app has a "Report" button that pre-fills the issue with
your context.

Brew Browser 0.7.0 / native 0.3.0 — Bundles

Choose a tag to compare

@msitarzewski msitarzewski released this 15 Jul 13:04
fbaaf45

brew-browser 0.7.0 / Brew Browser native 0.3.0 — Bundles

Signed + notarized release. Tauri is the macOS 13+ / Linux build; native is the
macOS 26 SwiftUI build. The two version numbers track the same feature batch
(native 0.3.0 ≙ Tauri 0.7.0); they differ only because each shell versions by
its own release history.

Headline: Bundles

Install a whole working setup in one place, not one package at a time.
Bundles are curated one-click package stacks — a local-LLM rig, an image-gen
studio, a web-dev starter — each with the packages it needs and the post-install
steps to make them actually work. A new Bundles section lands in both shells.

  • Nine recipes at launch, every token verified against brew info and
    drawing only on homebrew/core and homebrew/cask (zero third-party taps):
    Local LLMs, Image Generation, Graphics & Design, Media Toolkit, Web Dev
    Starter, Local Databases, Agentic Web Dev, LAMP Stack, and LEMP Stack.
  • Master list + Details pane. Bundles use the app's canonical master-list
    and right-side Details pane, matching Library and Trending exactly — nothing
    is auto-selected, the pane opens when you pick a bundle and closes when you
    dismiss it or switch sections.
  • Readiness gating. A zero-install system profile (RAM, architecture, GPU,
    disk) decides whether your Mac can actually run a stack, so an 8 GB machine
    isn't told to install a local-LLM bundle it can't support. A single header
    pill carries the verdict; a color-coded callout appears only when a bundle is
    marginal or blocked.
  • Intent up front. Each bundle leads with a short description paragraph
    explaining what the stack is for, rendered under the tagline.
  • Clickable inline package descriptions. Every package row is a disclosure
    that lazily fetches its one-line summary (catalog first, brew info
    fallback), cached, with multiple rows open at once.
  • Per-package Install. A "Not installed" package exposes an inline
    Install action that installs just that package through the streamed
    install path, keeps the Details pane open, and flips the row to Installed —
    independent of the description toggle.
  • Setup guidance that knows what it can automate. brew-native install steps
    run in-app and stream into the Activity drawer; external commands (model
    pulls, service bootstrapping, and the like) are presented copy-only rather
    than executed silently.
  • Contributor-friendly by design. Recipes are validated JSON files that
    anyone can PR against a published contract, with CI enforcing the schema. The
    long tail (Rails, Django, MEAN, and others) is open for community
    contributions.

Also in this release

Pin / unpin packages

Hold a package back from "Update all." Pinning works in both shells for
formulae and casks, with a Pinned filter tab in the Library, a
cask-aware pinned count, and a bottom status bar that leads with the active
filter's count. Closes the long-standing pin/unpin requests (#141; closes #90,
#134).

Resizable Activity console

The Activity console is now resizable in both shells, so you can give live
brew output as much room as you want (#136).

In-app brew command options

A reactive recovery UI surfaces adopt / overwrite / force-remove choices when a
brew job needs them, with an Advanced disclosure for greedy upgrades and
autoremove (#109; addresses #98 reactive, #47, #13, #102, #100).

Brew Doctor + Cleanup on the Dashboard

The Storage card gains two actions, both streamed into the Activity drawer:

  • Run brew doctor — runs brew doctor and shows diagnostics live
    (advisories are surfaced as info, not a failure).
  • Clean up cache…brew cleanup --prune=all to reclaim cached downloads,
    with a "frees ~X" estimate and a confirm step. --scrub (which also clears
    the current versions' downloads) is an opt-in toggle, off by default (#82,
    #83; issue #80).

Vulnerability scanning hardening

  • Exposure parity + native GHSA enrichment. The native build gains the
    source: live/cache label and GHSA enrichment, and the Tauri over-count is
    fixed, with unified card wording across both shells (#107).
  • Tap-name + JSON-salvage fixes. brew vulns now accepts tap-qualified
    formula names and salvages JSON from banner noise (#103; #62, #92).
  • Native catalog empty-response guard brings the native build to parity
    (#108).
  • GHSA advisory references shape fix. GHSA references are a string
    array, not [{url}]; the previous shape made enrichment a silent no-op. Now
    repaired and verified end-to-end (#110).

UX and correctness fixes

  • Native list scaling — content columns fit the narrow-window floor without
    clipping the sidebar (#142).
  • Install-trend sparkline scale — the sparkline no longer mixes cumulative
    and daily counts, removing the "cliff" artifact. Both shells (#143).
  • Tauri vulnerable-footer navigation — the vulnerable-count footer now jumps
    to Library → Vulnerable instead of the Dashboard (#144).
  • Native outdated tap-name undercount — tap-installed outdated packages are
    no longer dropped from the Outdated filter (#145).

Changes

  • Package metadata and docs aligned to the release train: Tauri 0.7.0, native
    0.3.0.

Acknowledgments

  • @cseelye — the resizable Activity console, contributed to both shells
    (#136).
  • @modeezie — the Brew Doctor / Cleanup cache-maintenance request, with a
    well-scoped "show me what it's doing" ask and the safer non-scrub default
    suggestion (#80).
  • @Arvuno — the catalog reject-empty-response fix that hardens the catalog
    refresh against upstream returning nothing (#101).
  • Everyone who filed the pin/unpin, brew-options, and vulnerability-scanning
    issues that shaped this batch.

Issues & feedback

github.com/msitarzewski/brew-browser/issues.
Every error toast in the app has a "Report" button that pre-fills the issue with
your context.

brew-browser 0.6.0 / native 0.2.0

Choose a tag to compare

@msitarzewski msitarzewski released this 13 Jun 18:27
fef4b87

brew-browser 0.6.0 / Brew Browser native 0.2.0 — feature-request batch

Signed + notarized release. Tauri is the macOS 13+ / Linux build; native is the
macOS 26 SwiftUI build. The two version numbers track the same feature batch
(native 0.2.0 ≙ Tauri 0.6.0); they differ only because each shell versions by
its own release history.

What's new

  • Reverse dependencies in package detail. Package pages show which installed
    packages require the selected formula ("Required by").
  • Deprecated / disabled indicators. Rows and detail panels surface Homebrew's
    deprecation and disablement metadata — with the upstream reason and any
    replacement token — instead of hiding lifecycle state.
  • Manual vs Dependency Library filters. Library filtering separates packages
    the user requested from formulae installed only as dependencies.
  • Per-package disk size. Package detail shows the on-disk Cellar/Caskroom
    footprint for installed packages.
  • Discover sub-categories. Within a selected Discover category, members are
    grouped by their co-assigned categories so broad buckets are easier to scan.
  • Friendlier failure notices. When a brew job fails, the Activity drawer now
    shows a concise, actionable notice instead of a raw error code. Casks that
    need an administrator password (e.g. docker-desktop) — which can't prompt
    under brew-browser's non-interactive brew — now explain to run the upgrade in
    Terminal, and name the cask.

Changes

  • The Dashboard "Recent changes" card has been withdrawn for this release while
    its presentation is reworked; it will return in a follow-up. No data is lost —
    the full history remains in the Activity view.
  • Package metadata and docs aligned to the release train: Tauri 0.6.0,
    native 0.2.0.

Acknowledgments

  • The Reddit feature-request feedback that shaped this batch.

brew-browser 0.5.1

Choose a tag to compare

@msitarzewski msitarzewski released this 07 Jun 05:50

brew-browser 0.5.1 — Reliability + a native sibling

Signed + notarized. macOS 13+, Apple Silicon. Auto-updates via the in-app updater.

This release also debuts a second build: a fully native Swift / SwiftUI
app for macOS 26 (Tahoe). Same features, same brew integration, same privacy
posture. See the README → "Two builds." The Tauri build below remains the
cross-platform one (macOS 13+ and Linux).

What's new

Live progress during installs and upgrades. Multi-package operations now show
a determinate progress bar with a per-package count — Pouring 10 of 32 — parsed
from brew's own ==> markers, instead of just a wall of streaming text. (#57)

The window remembers its size and position. Resize or move the window, quit,
and relaunch — it reopens exactly where and how you left it. (#17, #19)

The Dashboard fills in on launch. Your GitHub card, the vulnerability Exposure
card, and the sidebar badges now populate from cache on first paint, instead of
looking empty until you poked around.

Fresher catalog. The bundled Homebrew catalog was refreshed (8,404 formulae +
7,703 casks). Hit Refresh anytime for the latest.

Bug fixes

"Upgrade all" no longer cries failure when it succeeded. brew upgrade exits
non-zero on harmless post-install/link warnings even when every package upgraded;
the app treated that as a failure and nudged you to file an issue. Those non-fatal
cases are now reported as success — genuine failures still surface with a clear
message. (Resolves a large cluster of "[brew-browser] Upgrade-all failed" reports.)

"Top categories in your library" filters your library. Clicking a category in
that card now shows your installed packages in it, not the entire Discover
catalog. (#58)

GitHub sign-in is reliable and sticks. The credential is now stored as a single
Keychain item, so signing in is one prompt and the signed-in state persists across
launches (previously it could appear signed-in but not reflect in Settings). (#51)

Window stays draggable with Settings open. The Settings scrim no longer covers
the title bar's drag region. (#8, #10)

Acknowledgments

  • @neodave — path-traversal hardening in Brewfile/snapshot handling (#46).
  • @Arvuno — a friendly brew services launchd-domain hint (#51).
  • @bytepl (Maciej Chojnacki) — window-state report (#17).
  • @unluckyquote (Nik) — unmovable-window-with-Settings-open report (#8).
  • Reddit feedback that shaped this release: u/arcadefx1 (operation progress
    counts), u/HedgeHog2k and u/sikisabishii (library category filter).

v0.5.0 — Opt-in Vulnerability Scanning

Choose a tag to compare

@msitarzewski msitarzewski released this 28 May 22:51
636092e

brew-browser v0.5.0 — Opt-in vulnerability scanning

Signed + notarized. macOS 13+, Apple Silicon. Auto-updates from v0.4.0 via the in-app updater.

Highlights

You can now find out which of your installed Homebrew formulae have known CVEs — without leaving the app. v0.5.0 adds opt-in vulnerability scanning powered by the official brew vulns subcommand (Homebrew/homebrew-brew-vulns, by Andrew Nesbitt, published January 2026). When you turn it on, brew-browser shells out to brew vulns to query OSV.dev's GIT ecosystem for vulnerabilities matching your installed formula versions, then optionally enriches each finding with richer prose from the GitHub Advisories API.

Off by default. Both new toggles (vulnerability scanning + GitHub auth for enrichment) sit behind explicit consent in Settings → Network. No first-launch user generates a single OSV query without flipping the switch.

What's new

Opt-in vulnerability scanning. Settings → Network → Vulnerability Scanning toggles the feature on. When brew vulns isn't installed yet, the Settings card shows a one-click installer button that runs brew install homebrew/brew-vulns/brew-vulns for you and streams the output into the Activity drawer. After install, flip the toggle and the first scan kicks off automatically.

Dashboard Exposure card. A new card on the Dashboard shows your aggregate exposure: counts of critical / high / medium / low / unknown findings across all installed formulae, plus a "Scan now" button to force a refresh. When you're clean, the card shows a ✓ checkmark and "No known vulnerabilities" — the clean state IS the message, no collapsing.

Sidebar count badge. A small count badge on the Library nav item shows how many of your installed packages have at least one known CVE. The badge color tracks the highest severity (red for critical, orange for high, amber for medium, blue for low, grey for unknown). Hidden when the count is zero so the sidebar stays uncluttered.

PackageRow severity dots. Library rows get a small color-coded dot next to the installed pill when a package has known vulnerabilities. Hover for a tooltip; click through to the detail panel for the full list. The dots are synchronously hidden when the feature is off — no extra IPC chatter.

PackageDetail Security card. Open any installed formula's detail panel and you'll see a new Security card listing every CVE/GHSA finding for that package: severity pill, advisory ID (linked out to GHSA or OSV when there's a reference URL), summary text, and the version range where it's fixed. When the package is outdated AND at least one finding has a fixed_in range, an "Upgrade to fix" button is wired straight into the existing brew upgrade pipeline. A "Check vulnerabilities" button lets you force a per-package re-scan whenever you want.

Install-set fingerprint optimization. Daily scans on an unchanged install set serve from cache instantly. The backend records a SHA-256 fingerprint of your sorted kind:name:version lines alongside the scan results. On the next open, if nothing has changed, the cached report is returned without re-shelling brew vulns (which can take 60+ seconds with 200 packages). The "Scan now" button on the Dashboard Exposure card forces a full re-scan when you want the latest.

Refresh integration. When you click Refresh on the Dashboard or in Library — which now runs brew update, refreshes the catalog, AND reloads your installed list — the vuln scan re-runs as part of the same flow. So a refresh that learned about a new upstream version of openssl@3 and a new CVE for it shows you the security finding in the same beat as the new version number.

Post-mutation re-scans. Every install / upgrade / uninstall invalidates the affected cache entry and triggers a per-package re-scan, so the Security card and severity dot reflect reality immediately after you act — no stale ✓ from yesterday's pre-upgrade state.

How to enable

  1. Open Settings → Network → Vulnerability Scanning.
  2. If brew vulns isn't installed, click Install brew vulns. The output streams into the Activity drawer. Takes ~10 seconds.
  3. Flip the Enable vulnerability scanning toggle on.
  4. The first scan kicks off automatically. Larger install sets take longer; the Exposure card shows progress.
  5. Optional: in Settings → GitHub, sign in to GitHub if you want GHSA enrichment — richer summaries, patched-version ranges, and reference links from api.github.com/advisories. Without GitHub auth, you still get full OSV data; GHSA is purely a UX upgrade.

To turn it off later: flip the same toggle. The on-disk cache stays around (in case you turn it back on) but no scans run and no UI surfaces show vulnerability information. Offline Mode hard-locks the feature regardless.

Trust boundary

This is the first feature that involves an outbound path opened by a subprocess, not by brew-browser itself. The architecture is explicit so the privacy story stays auditable:

  • api.osv.dev — OSV.dev's GIT-ecosystem query endpoint. POST'd by brew vulns, not by brew-browser directly. We invoke the subprocess; the subprocess opens the socket. Same trust posture as every other brew call (the brew install you ran yesterday also opens sockets to GitHub, OCI registries, and bottle mirrors — and you'd see them in the Activity drawer if you looked).
  • github.com, gitlab.com, codeberg.org — source-URL and version-tag resolution by brew vulns so it can match your installed version against the vulnerable-version ranges OSV publishes. Same subprocess-as-origin posture.
  • api.github.com/advisories/{GHSA_ID} — GHSA enrichment from brew-browser's own Rust code, only when both Vulnerability Scanning AND GitHub Sign-in are on. Three independent toggles must align for a single request to leave the box: master Offline Mode off, vulnerability-scanning toggle on, github-enabled toggle on. Failure (rate limit, network error) leaves the OSV record unchanged and logs without bothering you.

Full server-side audit in memory-bank/security.md §17. The gate-composition table, threat model, and pre-launch checklist all live there.

Known limitations (honest gaps)

  • Casks aren't supported. brew vulns is formula-only. Cask packages render the same UI shell in the Security card but the body honestly says "Cask coverage isn't supported — brew vulns is formula-only." This isn't fake clean state; we'd rather be honest about the gap than tell you a package is safe when we have no idea.
  • Formulae with tarball-only sources may show empty results. brew vulns resolves vulnerabilities by mapping source URLs to upstream version tags in OSV's GIT ecosystem. Formulae whose source is a tarball without a corresponding Git tag may not match cleanly. This is rare in practice (most Homebrew formulae point at GitHub/GitLab releases that have both tarball and tag), but worth knowing about if a formula you expected to see findings for shows none.
  • GHSA enrichment is best-effort. If you've enabled GitHub sign-in, GHSA gives you richer data than OSV alone. But if api.github.com rate-limits you, throws a 5xx, or is unreachable, the enrichment quietly fails and you see the OSV record without the prose extras. No retry, no toast — the scan is reliable; the cherry on top isn't load-bearing.

What's NOT changed

  • Without opting in, nothing changes about your outbound posture. No OSV traffic, no GHSA requests, no brew vulns invocations. The previous ten outbound paths from v0.4.0 are unchanged.
  • The Settings UI keeps the same shape. The new Vulnerability Scanning section sits at the bottom of Network alongside the existing Updates and Enhanced Trending History subsections — same nested-subsection pattern, same "locked off" treatment when Offline Mode is on.
  • No new dependencies in the frontend. The store, types, and components are pure additions.
  • Two new Rust dependencies (sha2, hex) for the install-set fingerprint. Both are widely used; SHA-256 is the right primitive here because Rust's DefaultHasher is non-deterministic across process runs (its salt is randomized to defeat HashDoS) — a hash recorded to disk would mismatch every subsequent launch.

Under the hood

  • +78 backend tests (507 → 585). Pin the new gates exhaustively: toggle off → FeatureDisabled, paranoid on → ParanoidModeBlocked, FirstLaunch → FeatureDisabled (opt-in preserved), Corrupt settings → ParanoidModeBlocked (fail-closed), forward-compat for v0.4.x settings.json missing the new field, formula name validator rejects shell metas + empty + oversize, cache TTL is 6 hours, fingerprint is order-independent, GHSA enrichment short-circuits when github_enabled is off. +6 of those tests are a captured-fixture pin against real brew vulns --json output — the live smoke test on a 326-package install caught five integration assumptions that were wrong (severity wire is UPPERCASE; fixed_versions is an array not a string; install-detection needed brew --prefix brew-vulns, not brew commands; --include-aliases needs --quiet; brew-vulns exits 1 on findings per CI-scanner convention). All five are now regression-pinned and commented at the trap sites.
  • One new error variant vulns_not_installed in the BrewError union, with a friendly message routing the user to the one-click installer (not a generic exit-non-zero toast).
  • Two on-disk caches at ~/Library/Application Support/brew-browser/: vulns_cache.json (1 MiB cap, 6h per-record TTL) for scan records + the install-set fingerprint; ghsa_cache.json (2 MiB cap) for the enrichment payloads. Both fail soft on corrupt + future-schema — no first-launch user can be wedged by a bad cache file.

Acknowledgements

Read more

v0.4.0 — Trending Velocity + Opt-in History Endpoint

Choose a tag to compare

@msitarzewski msitarzewski released this 26 May 22:54
090b9e1

brew-browser v0.4.0 — Velocity scoring + Star-History for Homebrew

Signed + notarized. macOS 13+, Apple Silicon. Auto-updates from v0.3.1 via the in-app updater.

Highlights

Trending now sorts by velocity, not raw count. The old Trending tab was a leaderboard of dep-pulled packages — ca-certificates, openssl@3, git always on top because everything depends on them. v0.4.0 fixes that by computing a per-package velocity index from the three rolling-window install counts Homebrew publishes (30d, 90d, 365d). The math is "this month's installs vs the prior eleven months' average month" — 1.0 is steady, 1.5+ is surging, 0.5 or below is cooling. The Trending tab defaults to sorting by velocity desc with 🔥 / ❄️ badges on each row. The result is what's actually accelerating right now, not what's already big — and packages with zero prior history are filtered out so a brand-new tap doesn't auto-pole-position the leaderboard.

install-on-request signal. The Trending tab now fetches Homebrew's install-on-request analytics endpoint in parallel with the primary install endpoint. The first counts installs users explicitly typed brew install <foo> for; the second includes everything pulled in as dependencies. Both numbers are available on each row internally, with the leaderboard-dominator metric (install) staying as the visible Installs column and the user-intent metric feeding the velocity computation underneath. Together they de-noise the trending signal dramatically.

Star-History for Homebrew (opt-in). When you enable Enhanced Trending History in Settings → Network, you get:

  • Inline mini-sparklines on every Trending tab row, showing each package's install trajectory at a glance
  • A full install-trend chart on each package's detail panel
  • Server-precomputed velocity index that updates nightly (independent from the per-window-fetch computation)

This data comes from a new project-operated endpoint at brew-browser.zerologic.com/trending-history/*. It's the first outbound path in brew-browser's history that goes to infrastructure we control (rather than upstream Homebrew or GitHub), so it gets an explicit opt-in toggle and lives in its own section of the disclosure list at the bottom of Settings → Network. Off by default. Offline Mode hard-locks it off regardless. Only the package name you're viewing is sent (one HTTP GET per package); no IP is logged, no cookies, no fingerprinting. The Caddy log-redaction config that makes the privacy claim auditable is published in memory-bank/security.md §16.

The day-zero seed trick. When you opt in on day one, the historical chart isn't empty — the collector that runs on brew-browser.zerologic.com bootstraps three historical "buckets" per package from rolling-window subtraction (last 30 days, days 31–90, days 91–365). From that point forward, the nightly collector accumulates real daily snapshots; after ~30 days you have clean per-day install estimates. The historical bars fade into the background as the real daily resolution builds up on the right edge of every chart.

Settings → Network reorganization

New disclosure entry (10th in the list, was 9):

brew-browser.zerologic.com/trending-history
Enhanced trending history — opt-in, off by default

New nested subsection at the bottom of Network alongside the existing Updates panel. Single toggle, clear hint copy explaining what's sent, what's logged (nothing identifiable), what's not. Disabled with a "locked off" indicator when Offline Mode is on.

What's NOT changed

  • Without opting in, nothing changes about your outbound posture. Velocity sorting and the 🔥/❄️ badges work entirely from the always-on Homebrew analytics endpoints. The only new behavior is "Trending sorts differently by default" — and you can still pick any other sort key from the column headers.
  • The previous nine outbound paths are unchanged. README's disclosure section has been updated to enumerate all ten (path j = the new endpoint).

Under the hood

  • +33 backend tests (473 → 506). Pin the new gates exhaustively: toggle off → FeatureDisabled (distinct from ParanoidModeBlocked so toasts route correctly), paranoid on → ParanoidModeBlocked regardless of the per-feature toggle, FirstLaunch → FeatureDisabled (opt-in posture preserved), Corrupt settings → ParanoidModeBlocked (fail-closed via inner gate), URL builder for the per-package fetch rejects path traversal exhaustively (../, spaces, ;, etc.).
  • One new dependency on the backend: none. Velocity math is pure Rust in src-tauri/src/trending/velocity.rs; the parallel install + install-on-request fetch reuses the existing reqwest client. The history endpoint client is a thin GET wrapper.
  • One new dependency on the collector: better-sqlite3. The collector is a separate Node 20+ ESM project at tools/trending-collector/ that ONLY runs on brew-browser.zerologic.com — the brew-browser app itself doesn't pull this in.
  • New error variant feature_disabled in the BrewError union, mirrored in BrewErrorPayload with a friendly message that routes the user to Settings → Network rather than the master Offline Mode switch.

Acknowledgements

Velocity-as-the-Trending-sort idea came from a user observation: "Trending needs more algo though. It's straight from the brew APIs. We need velocity, right?" The seed-from-rolling-windows bootstrap trick followed from "Use A to create B's first debut. Then we can watch with real data from then on?" — using the same three windows we already fetch to give the historical chart something to show on day zero.

Star-History inline-row sparkline aesthetic borrowed from star-history.com's trending repo list.

Issues & feedback

github.com/msitarzewski/brew-browser/issues. Every error toast in the app has a "Report" button that pre-fills the issue with your context. Use it liberally — it's literally what the button is for.

v0.3.1 — Magic search, real Refresh, cleaner identity

Choose a tag to compare

@msitarzewski msitarzewski released this 26 May 03:36

brew-browser v0.3.1 — Magic search, real Refresh, cleaner identity

Signed + notarized. macOS 13+, Apple Silicon. Auto-updates from v0.3.0 via the in-app updater.

Highlights

Magic search. Search now matches against everything brew-browser knows about — not just package names. Try queries like:

  • video player — finds VLC, mpv, MPlayer (matches AI summaries)
  • password manager — finds 1Password, Bitwarden, KeePassXC
  • AI or LLM — finds ollama, llm, openai-cli, llama.cpp
  • Video & Audio — returns every package in that category
  • terminal emulator — iTerm2, Alacritty, kitty, WezTerm

Behind the scenes: a new in-process local_search IPC scans the bundled catalog + AI summaries + friendly names + category labels + (eventually) Tier B tags, scores each hit by field weight (name > friendly > category > summary > desc > tag), and returns top results in well under 20ms — much faster than the previous brew search shell-out.

Unified Description + Version columns. Library, Discover, and Trending list views now share the same canonical row layout: (icon/rank) | NAME | DESCRIPTION | VERSION | TYPE | TRAIL. The Description column prefers the AI-generated summary when available, falls back to the upstream Homebrew desc. Friendly name still appears as a short subtitle below the token for scan-aid.

Curated Upgrade UX. The Updates card on the Dashboard gains a "Choose…" button next to "Upgrade all". Click it to see every outdated package with a checkbox, name, current → target version, and a pinned badge. Pick which ones to upgrade this round; the modal fires one batched brew upgrade <a> <b> ... streaming into the Activity drawer.

Refresh actually refreshes everything. The Refresh button now runs brew update (so brew learns about new upstream versions), refreshes the bundled catalog from formulae.brew.sh, AND reloads your installed list — in that order, streaming the brew update output to the Activity drawer. Previously Refresh only updated the catalog index, leaving outdated flags stale until you ran brew upgrade in a terminal.

Donut chart hover-with-counts. Hover any slice (or its matching legend row) on the Dashboard's "Top categories" donut: the slice fattens, the others dim, and the center text takes over with {count} / {label}. Click the legend row to jump straight to that category in Discover.

Report-to-brew-browser on every error. Error toasts now carry a "Report to brew-browser" button that opens a pre-filled GitHub new-issue URL with your brew-browser + Homebrew versions, the failing command, exit code, stderr excerpt, and the friendly message brew-browser tried to show you. Same button surfaces in the Activity drawer when a job fails.

Friendly error messages. Ten toast sites that previously rendered the raw error code (brew_exit_non_zero) now render the actual friendly message from the backend. Among other things, this means the shiva brew bundle dump topo-sort crash now surfaces with the "this is an upstream Homebrew bug, not a brew-browser issue" guidance it was always meant to.

Quieter improvements

  • Bundle identifier cleaned up: dev.openbrew.browsercom.zerologic.brew-browser. v0.3.0 users will be prompted to re-sign-in to GitHub once (Keychain ACLs are tied to the old identifier; no migration is possible without re-prompting anyway). One-click via the "Re-authorize" toast button that already ships.
  • Activity history is more durable. Cap raised from 50 jobs to 200. startJob now persists immediately instead of waiting for the 400ms debounce. Persist + hydrate failures now log to the console instead of silently swallowing.
  • brew_list cache invalidation. Adding force=true to the IPC; the Refresh button uses it. Previously a stale installed_cache could mask brew upgrade runs from your terminal until process restart.
  • Stale "Paranoid mode is on" toast wording still slips through the central brewErrorMessage for paranoid_mode_blocked. The rename to "Offline Mode" was applied everywhere else; this one was missed in Phase 15 and got carried forward — fix landed in this release.

Under the hood

  • 473 backend tests passing.
  • CatalogEntrySummary gains a version: Option<String> field so the new Version column can render without per-row IPC.
  • Activity drawer's failed-job footer gains a "Report to brew-browser" button next to the failure summary.
  • tauri-plugin-dialog was already wired since v0.1.0 (catching up the realityCheck doc with a post-audit footnote).
  • Memory bank reorganized: BUILD.md, PHILOSOPHY.md, PLAN.md moved from repo root to docs/; phase15-plan.md moved to memory-bank/phases/ now that Phase 15 has shipped.

Install

If you're on v0.3.0, click Refresh on the Dashboard or open Settings → Network → Updates → Check now. The in-app updater will pick this up, verify the signed .app.tar.gz against the embedded minisign pubkey, and replace your installed .app atomically. Click Relaunch now when it finishes.

For fresh installs, the .dmg is on the GitHub release page. Drag to Applications. macOS Gatekeeper accepts it cleanly (signed + notarized + stapled).

Acknowledgments

  • @heyjawrsh for the issue-#1 flow that drove the friendly-message + Report-to-brew-browser work.

Full diff: v0.3.0...v0.3.1

v0.3.0 — In-app updater + GitHub coverage + issue #1 fixes

Choose a tag to compare

@msitarzewski msitarzewski released this 25 May 12:09

brew-browser v0.3.0 — In-app updater + GitHub coverage + issue #1 fixes

Signed + notarized. macOS 13+, Apple Silicon.

Highlights

In-app updater. brew-browser now tells you when a new version exists. A title-bar pill appears when a newer release is detected; Settings → Network → Updates owns the manual "Check now" button, the off-by-default daily auto-check, and the install action. Every artifact is verified against an embedded minisign public key before any on-disk side effect (sha256 first, then signature — mismatch aborts with no install). Skipping a version is per-release, so a future update re-triggers the notice.

"Offline Mode" instead of "Paranoid Mode." Same kill switch, friendlier name. Toggle in Settings → Network blocks every outbound feature: catalog refresh, trending, GitHub, updater. The internal field stays paranoid_mode to avoid migrating existing settings files.

GitHub coverage expansion. Packages like bat, fd, ripgrep, tealdeer — marketing-page homepages but GitHub-hosted source — now light up Star / Watch / File-issue / Stats. Backend walks homepageurls.stable.urlurls.head.url (formula) or homepageurl (cask). The Dashboard's personal-stats card sees a bigger denominator.

GitHub Octocat status chip in the title bar. Green when signed in with required scopes, amber when a scope is missing (click → Settings → GitHub to re-authorize), hidden when signed out.

Actionable Re-authorize toast. If an action fails because your token doesn't carry the required scope (typical for tokens minted before v0.3.0 added notifications scope for Watch), the failure toast offers a one-click "Re-authorize" button. GitHub's consent screen shows only the missing scope. No sign-out needed.

Issue #1 fixes. Resolves the toast cascade on disconnect/reconnect that @heyjawrsh reported. Root cause was a cache loop in PackageDetail hammering Svelte's scheduler combined with a structural misuse of $effect for one-shot side effects. Star, Watch, File-issue, and the sign-in flow all work cleanly now.

Under the hood

  • 473 backend tests passing (up from 411 in v0.2.1).
  • Tauri 2 in-app updater plugin with embedded minisign pubkey + sha256 manifest verification.
  • Per-action OAuth scope gating — Star/File-issue need public_repo, Watch/Unwatch need notifications. The gate runs server-side before any GitHub round-trip.
  • New extract_github_repo tolerant URL parser that handles archive + release URLs (.../archive/refs/tags/v1.2.3.tar.gz, .../releases/download/v1.2.3/foo.dmg) while applying every strict-parser defense (host, scheme, character set, path traversal).
  • Lazy Keychain probe preserved — fresh launches still don't trigger the macOS "wants to use your confidential information" prompt unless you actually use a GitHub feature.

Install

Download brew-browser_0.3.0_aarch64.dmg, double-click, drag to Applications. macOS Gatekeeper will accept the signed + notarized binary without warnings.

If you're on v0.2.1, the in-app updater will surface this release after you upgrade once — manual .dmg installs are still supported but the auto-updater path is the recommended cadence going forward.

Acknowledgments

  • @heyjawrsh for filing issue #1 with a clear reproduction. Six hours of debugging surfaced two genuinely interesting Svelte 5 rabbit holes; the diagnosis is in memory-bank/tasks/2026-05/14-issue-1-hunt-cache-loop.md and 15-github-integration-completion.md for the curious.

Full diff: v0.2.1...v0.3.0

brew-browser v0.2.1

Choose a tag to compare

@msitarzewski msitarzewski released this 24 May 18:47

brew-browser v0.2.1

Hotfix on top of v0.2.0 — addresses three GitHub-auth issues users hit immediately, plus a few quality-of-life touches.

Fixes

macOS Keychain prompt on every launch

v0.2.0 eagerly probed the Keychain on app start to know whether you were signed in to GitHub. macOS treats a new binary signature as a new app for ACL purposes, so fresh installs of v0.2.0 fired the "brew-browser wants to use your confidential information stored in dev.openbrew.browser" prompt on every launch — even users who'd never touched a GitHub feature.

v0.2.1 makes the Keychain probe lazy: the OS prompt only fires when you actually click Star / Watch / File-issue, or open Settings → GitHub. If you never use a GitHub feature, the Keychain is never touched, and the prompt never fires. When it does fire, it's contextual — you're about to use the token, the prompt is meaningful.

GitHub auth toast bugs

  • "Signed in as @github user." — the post-sign-in success toast was reading status.username before the username had been fetched. Fixed: status loads before signinState flips to approved.
  • Stack of duplicate "Signed in to GitHub" toasts — the toast effect re-ran on every status hydration. Fixed: untrack() wrapping in the Svelte 5 effect so it's pinned to one toast per real state transition.

Star / Watch / File-issue worked correctly when authed

v0.2.0 bounced authenticated users to Settings → GitHub instead of running the action. This is the same root cause as the Keychain prompt — fixed in the same patch (lazy probe in requireGithubSignIn).

Small things

  • Real screenshots — the README and landing page now show actual product UI (Dashboard light/dark + Services). Landing's hero <picture> uses prefers-color-scheme so visitors see the screenshot matching their system theme.
  • Accurate build credit — "Powered by Anthropic's Claude Opus 4.7 and the Claude Agent SDK" → "Powered by Claude Code in the terminal, running Opus 4.7 [1m]." Claude Code is the runtime (this CLI), Opus 4.7 [1m] is the model.
  • gitleaks allowlist — added .gitleaks.toml allowlisting the public OAuth Device Flow client_id. Per RFC 8628 §3.1, Device Flow client_ids aren't credentials; the false-positive flag was the only thing gitleaks caught.

Security audit re-run

Full tool battery passed against the v0.2.0/v0.2.1 surface:

Tool Result
cargo audit 0 vulnerabilities
cargo deny check advisories ok, bans ok, licenses ok, sources ok
npm audit --omit=dev 0 vulnerabilities
semgrep (security-audit + OWASP-10 + Rust + TS, 113 rules, 104 targets) 0 findings
gitleaks 0 leaks (after allowlist)

Verdict: READY-FOR-SCRUTINY preserved. Full breakdown in memory-bank/security.md §14.

Install

Download the signed + notarized .dmg below, open, drag to Applications. No Gatekeeper warning. macOS 13 (Ventura) or newer · Apple Silicon.

Full changelog

v0.2.0...v0.2.1

Built with Agency Agents, by the creator of Agency Agents. Powered by Claude Code in the terminal, running Opus 4.7 [1m]. If brew-browser saves you time, sponsor on GitHub ♥.