BenchBar 0.5.0
BenchBar grows from a start and stop button into the place you run your
benches from: a window with every bench's sites, apps and health, Repair
from the app, a log window, apps from any GitHub repository (private
ones too), team profiles and a lockfile for the whole team, benchbar pull for a production copy, and benchbar mcp for coding agents. A new
app icon, and the window uses the macOS 27 tab style and Liquid Glass
buttons (older macOS versions get the classic look).
Added: the app
-
The BenchBar window replaces the sparse Settings window: General,
Menu Bar, Team Profiles and About, then a page per bench with Overview
(actions, ports, the scheduler), Sites (add a site with its
Administrator password, make one the default, the hosts fix), Apps (add
from the registry or any GitHub URL, public or private, install on a
site, update after a changelog preview) and Health (doctor, and Repair
with the plan first and a live step list). The popover links into it
(⌘M) and offers Repair when doctor found something repairable. -
A new app icon: the menu bar runner, a park bench on the run, drawn
for Icon Composer (macos/BenchBar/Resources/AppIcon.icon,
scripts/app-icon.py). -
A log window per bench (⌘L): follows
logs/bench.logwith smart
scroll, search with a match count and next and previous (⌘G, ⇧⌘G), a
filter per honcho process, errors and tracebacks in red, the previous
log, clear, select and copy, and Open in Terminal. It survives the
runner's log rotation and keeps at most 5000 lines.
Added: the command line
-
benchbar mcp: a Model Context Protocol server on stdio (stdlib only
Python) withbenchbar_list,benchbar_status,benchbar_doctor,
benchbar_logs_tail,benchbar_site_list,benchbar_up,
benchbar_downandbenchbar_restart, each backed by the CLI's JSON. -
benchbar logs --jsonwith-nNand--process NAME. -
benchbar repair --jsonstreams a plan, a step event per action and a
done event with the exit code;--dry-run --jsonprints only the plan. -
App commands.
benchbar app list [--json] [--no-sites]shows every
app with its branch, commit, local changes, shallow clone, version,
theapps.tsvbranch and the sites that have it (read with
bench list-apps, cached per bench).app add NAME|URLgets an app
fromconfig/apps.tsvor any git URL (GitHub over HTTPS, SSH, or an
SSH host alias from~/.ssh/config), with--branch,--name, and
--site Sor--all-sites: it checks access first with a git that
never prompts, so a missing key or token fails in a second with a fix
line, clones withbench get-app --skip-assets(never--overwrite
or--resolve-deps), clones therequired_appsofhooks.pyafter
a second plan, installs on the sites, builds once and restarts a
running bench. A half finished clone moves to the backups.app install NAME --site Sinstalls an app the bench has.app update NAMEfetches, shows the changelog, backs up every site that has the
app, fast forwards, runs requirements, migrate and build; it refuses
a dirty tree, a detached HEAD or a diverged branch, and on a failure
prints (never runs) the way back.app update --dry-run --jsonis the
plan for the app. -
Doctor checks
apps_txt(anapps.txtline without its folder
fails, a git app missing fromapps.txtwarns) and
app_branch_policy(an app off itsapps.tsvbranch warns). Both
read only local files and git;repairhas no action for them. -
Team profiles: an organisation's bench recipe in a TOML file outside
BenchBar, in~/.config/benchbar/profiles/NAME.tomlor a folder on
BENCHBAR_PROFILE_PATH(a clone of the team's config repo). It names
a built inbasefor Python, Node and MariaDB, an optional
frappe_branch, abundleor[[apps]]with repo, branch and an
optional commit, and optionalsiteandscheduler.benchbar install --profile NAMEuses it, and the bench keeps following it.
benchbar profile list [--json],profile show NAMEandprofile create NAME --from-bench PATH [--dir DIR](reads a bench, never
writes a credential or a commit). A team profile may not shadow a
built in one. -
The team lockfile
benchbar.toml: every app's repo, branch and
commit inapps.txtorder, and each site with its apps, in the same
strict TOML subset.benchbar lock writewrites it from the bench
(refuses local changes or a detached HEAD unless--allow-dirty,
--no-commitsfor branches only, shows the diff, backs up the old
file),lock check [--json]reports drift (13 kinds, from a missing
app to a site without an app) with no network or database, andlock applyclones missing apps, switches clean apps to the locked branch
and fast forwards to pinned commits, then runs requirements and
build. It never touches a site, never resets local work (ahead,
diverged and dirty apps are skipped), and prints the site steps to run
by hand.--lock PATH(remembered per bench) orBENCHBAR_LOCK
points at a file kept in the team's app. Doctor gainslock_parse
andlock_drift;list --jsongainsbenches[].lock_file. -
Access checks before cloning (phase 01 and
app add) run git with
GIT_TERMINAL_PROMPT=0and SSH in batch mode, so a private repo fails
at once instead of waiting on a prompt.
Added: pull
benchbar pull HOST:SITE --as NAMEcopies a production site over SSH
into a new local site. It uses the latest backup that already exists on
the server, so a plain pull writes nothing there;--new-backupruns
bench backupfirst, after the production site name is typed (or
given with--confirm-site), because that also deletes older backups
on the server. The download resumes (rsync --partial,scpwhen the
server has no rsync) into<bench>/.benchbar/pulls/, mode 0700.- The copy keeps its stored passwords: the production
encryption_keyis
written into the new site config through stdin and never shown or
logged, and a probe counts the encrypted rows that decrypt. Encrypted
backups are decrypted locally withgpg --passphrase-fd 0. - Before the restore, pull compares the production apps with the bench
and stops with thebench get-appcommands when one is missing
(--skip-app APPrestores without it and says what that leaves
behind), and stops when production frappe is newer than the bench. - After the restore:
mute_emails,pause_schedulerand
disable-scheduler(unless--keep-scheduler),host_name, the
removal of skipped apps,bench migratewhen the apps differ,
clear-cache, an optional Administrator password (ADMIN_PASSWORDor
a prompt, on stdin), the hosts line, and a verify pass. --replacerestores over an existing local site after a
bench backup --with-filesof it;--from-dir DIRrestores a backup
set downloaded by hand (Frappe Cloud);--dry-runconnects read only
and prints the plan;--jsonstreamsplan,gate,progress,
stepanddoneevents (docs/json-schema.md).
Changed
- The window's settings panes are laid out like System Settings: a
header per pane, Startup, Notifications, Command line tool and
Keyboard shortcuts on General, a runner preview on Menu Bar. The
sidebar's benches have a context menu (start, stop, restart, open,
show, copy path). app add URLfor an app inconfig/apps.tsvfollows its branch there
when the repository has it, instead of the repository's default
branch, so doctor does not warn about an app it just added. Raven's
registry entry points atgithub.com/frappe/raven.bench new-sitegets the MariaDB root and Administrator passwords on
stdin, never in its arguments.- CI runs the CLI tests in three parallel macOS shards (about 4 minutes
per pull request, from about 13); the Linux job is gone.
Fixed
app updaterefuses to run when a site's app list cannot be read, so
it never skips a site's backup or migrate.pullinto a running bench pauses the bench's scheduler until the
copy has its ownpause_schedulerandmute_emails.- A git repository or branch from a team profile or lockfile can no
longer be read as a git option (--everywhere, values starting with
-refused). - The window no longer jumps wider when you open General, and a
change's result shows only on the page it belongs to.
This build is not signed with an Apple Developer ID (ad hoc signature). macOS shows "Apple could not verify" on first open of the DMG: use System Settings > Privacy & Security > Open Anyway, or install with the one liner, which downloads with curl and opens without that prompt:
curl -fsSL https://raw.githubusercontent.com/askysh/benchbar/main/install.sh | bashChecksums are in SHA256SUMS.
The app in this release was built on a Mac with Xcode 27 (the macOS 27 tab style needs its SDK; the CI runners have Xcode 26.6) and is ad hoc signed like earlier releases. SHA256SUMS covers both files.