A native, leak-free macOS menu-bar script runner — the modern successor to xbar and SwiftBar.
Every xbar plugin. None of the memory leaks. Run any script in your menu bar — and see what it touches before you install it.
Vee runs plugins — any executable, in any language — on a schedule and renders their standard output as menu-bar titles and dropdown menus. Your existing xbar/SwiftBar plugins run unchanged; Vee adds a native AppKit UI, a trust/transparency layer, a built-in plugin catalog, and typed SDKs (TypeScript, Python, Go).
The bottom row is a real capture of the shipped build running on macOS 26.
- Native and leak-free — pure Swift 6.2 / SwiftUI + AppKit (
NSStatusItem/NSMenu), Liquid Glass UI, zero third-party dependencies. No embedded WebView in the menu; subprocess output is drained incrementally and processes are timed out and killed, so long-running use doesn't leak memory. - Runs the existing ecosystem — the full xbar/SwiftBar plugin protocol (filename intervals,
---/--menus,|params,<xbar.*>/<swiftbar.*>headers, SF Symbols, ANSI, Markdown, streaming, cron) works on day one. - Transparency, not a sandbox — plugins run un-sandboxed by design (the model requires it), but they can declare what they touch via
<vee.*>tags, and Vee shows a plain-language trust summary before install plus trust badges in the Manager. Advisory, never enforced. - Configuration belongs to the plugin —
<xbar.var>declarations become an auto-generated settings form; secret fields are masked and stored in the macOS Keychain. The app never hardcodes service names or credentials. - Discover — a built-in browser over the shared
matryer/xbar-pluginscatalog, with trust chips and one-click install through the trust gate. - Optional typed SDK — write plugins in TypeScript with
Menu/Sectionbuilders; Node runs the.tsdirectly, no build step.
- macOS 26 or later
- Apple Silicon (arm64) — there is no Intel build
Vee is distributed Developer-ID-signed and notarized, outside the Mac App Store (the App Store sandbox is incompatible with arbitrary plugin execution).
Vee ships as one binary that is both the menu-bar app and the vee CLI, so
installing gets you both.
Homebrew (recommended):
brew install --cask navbytes/tap/veePuts Vee.app in /Applications and vee on your PATH. brew upgrade --cask vee
picks up new releases.
Or one line, without Homebrew:
curl -fsSL https://vee.navbytes.io/install.sh | bashSame result — app in /Applications, vee linked into ~/.local/bin (or
/usr/local/bin). Re-run it to upgrade. Read it first if you would rather not
pipe a script to a shell: scripts/install.sh.
The installer takes three options, so you are not stuck with its defaults. Pass
them after bash -s --:
# Install per-user instead of system-wide
curl -fsSL https://vee.navbytes.io/install.sh | bash -s -- --app-dir ~/Applications
# Put the CLI somewhere else on your PATH
curl -fsSL https://vee.navbytes.io/install.sh | bash -s -- --bin-dir /opt/homebrew/bin
# Pin a specific release rather than the latest
curl -fsSL https://vee.navbytes.io/install.sh | bash -s -- --version v0.2.0| Option | Environment | Default |
|---|---|---|
--app-dir DIR |
VEE_APP_DIR |
/Applications |
--bin-dir DIR |
VEE_BIN_DIR |
first writable of ~/.local/bin, /usr/local/bin |
--version TAG |
VEE_VERSION |
the latest release |
Not
VEE_APP_DIR=… curl … | bash. That sets the variable forcurl, not for thebashreading the script, so it is silently ignored. Use a flag, orexportthe variable first.
Just the CLI, via mise:
mise use github:navbytes/veeThis is the CLI only — vee render, vee lint, vee dev, vee new. mise puts
binaries on your PATH; it does not install the menu-bar app. Use it when you want
the CLI pinned per-project, or on a machine that only needs the tooling.
Or download directly:
- Download the latest
Vee.appfrom GitHub Releases. - Drag it into
/Applications. - Launch it. On first launch, if Gatekeeper prompts, right-click
Vee.app→ Open and confirm.
Plugins live in ~/Library/Application Support/Vee/plugins by default (Vee creates this folder on first launch; change it in the Plugin Manager → Choose Folder). A plugin's filename encodes its refresh interval: name.INTERVAL.ext.
Create the folder if you haven't launched Vee yet, then add hello.5s.sh:
mkdir -p ~/Library/Application\ Support/Vee/plugins#!/bin/bash
echo "Hello 👋"
echo "---"
echo "It works!"
echo "Refresh | refresh=true"Make it executable:
chmod +x ~/Library/Application\ Support/Vee/plugins/hello.5s.shThe .5s runs it every 5 seconds. The line before --- is the menu-bar title; everything after is the dropdown. Full reference: Plugin authoring.
Point Vee at your existing plugins folder (Plugin Manager → Choose Folder) — that's the whole migration. The entire xbar/SwiftBar protocol is supported, and Vee injects the same environment variables (XBARDarkMode, SWIFTBAR_*, OS_*), so plugins run unchanged. Caveats: macOS 26+ and Apple Silicon only. See Migrating from SwiftBar/xbar.
- xbar/SwiftBar-compatible plugin format (titles, submenus,
|params, metadata headers) - Filename refresh intervals (
ms/s/m/h/d) and<swiftbar.schedule>cron - SF Symbols, ANSI color, inline Markdown, emoji shortcodes
- Streaming plugins (
~~~) with restart/backoff - Rich menu rows:
progress=gauges,sparkline=trends,pie=/donut=/stackedbar=share charts, and livetoggle=/slider=controls — drawn with AppKit and Swift Charts, no WebView - Detached plugin windows: Open in Window leaves a plugin's whole menu open on the desktop, live on its own refresh interval
- Searchable filter panel (opt-in
<vee.filter>): fuzzy-search a plugin's whole nested menu from a Spotlight-like popover, with an optional global hotkey (<vee.shortcut>) - Declared typed preferences → auto-generated forms; secrets in the Keychain
<vee.*>trust declarations → plain-language trust summary + badges- Discover: catalog browser with one-click, trust-gated install — over the public catalog or your own custom/enterprise store (a GitHub repo, GitHub Enterprise, static host, or air-gapped mirror)
- Plugin Manager: enable/disable, per-plugin settings, reveal in Finder, choose folder, launch-at-login, refresh all
vee://andswiftbar://URL actions- Desktop widgets (Notification Center): a configurable per-plugin status tile with gauges/sparklines, a Vee Health roll-up, and a Control Center Refresh Vee control
- Zero-dependency typed SDKs (TypeScript, Python, Go) with golden-fixture drift guards
vee devsave-driven authoring loop: watch a file, re-render on every save, optionally preview it as a real menu-bar item
- Getting started
- Migrating from SwiftBar/xbar
- Plugin authoring reference
- Trust model
- Custom plugin stores (enterprise)
- Preferences
- Plugin SDKs (TypeScript, Python, Go)
- JSON output format
- CLI and URL actions
- Architecture (for contributors)
- FAQ
- Troubleshooting
A plugin is any executable that prints text to stdout — bash, Python, Ruby, a compiled binary, anything. For a new plugin, printing Vee's structured-JSON format ({"vee":1,…}) is the recommended way to start: typed booleans and numbers, no |-param quoting, and clean nesting for submenus. The xbar/SwiftBar text protocol is still fully supported — it's how every existing xbar/SwiftBar plugin keeps working unchanged — and is documented in full in the plugin authoring reference. See plugins/showcase/ for ready-to-run examples of both, including kitchen-sink.1m.sh, one file exercising every JSON field.
Download and run that one file to see everything — every JSON field in one plugin:
curl -o ~/Library/Application\ Support/Vee/plugins/kitchen-sink.1m.sh \
https://raw.githubusercontent.com/navbytes/vee/main/plugins/showcase/kitchen-sink.1m.sh
chmod +x ~/Library/Application\ Support/Vee/plugins/kitchen-sink.1m.shFor the edit loop, keep vee dev in a split terminal beside your editor — it re-runs the file and repaints the menu on every save:
vee dev ./cpu.10s.sh # run it and re-render on save
vee dev --text menu.txt # preview protocol text, executing nothing
vee dev --push ./cpu.10s.sh # also show each save as a real status item
vee lint --format compact FILE # diagnostics your editor can place on a linePrefer typed builders to hand-formatting text? Vee ships zero-dependency SDKs in three languages, each with Menu/Section builders and typed builders for the rich params (sparkline/toggle/slider/progress/chart) so quoting and escaping are handled for you:
- TypeScript (
plugins/) — Node 24+ runs the.tsdirectly, no build step. - TypeScript (
plugins/typescript/) — zero-dep, Node runs it directly. - Python (
plugins/python/) — standard library only. - Go (
plugins/go/) — standard library only.
A golden-fixture drift guard shared byte-for-byte across all three keeps every SDK and the Swift parser in lockstep.
Vee runs plugins un-sandboxed with your privileges — a real sandbox would break the plugins people want to run, which is why apps in this category ship outside the App Store. Instead of pretending to isolate plugins, Vee makes them transparent: authors declare network domains, filesystem paths, secrets, and external binaries via <vee.*> tags, and Vee shows a plain-language summary before install and trust badges in the Manager. It's advisory, never enforced — read the source of anything you don't trust. Details: Trust model.
swift build # build the libraries + dev executable
swift test # run the test suites
swift run vee # run the menu-bar app for development
# Build the distributable app bundle:
xcodegen generate
xcodebuild -project Vee.xcodeproj -scheme Vee buildRepository layout:
Sources/
├─ VeeCore/ # primitives: RefreshInterval, PluginFilename, clock, errors
├─ VeePluginFormat/ # the xbar/SwiftBar output + header parser (pure)
├─ VeeRuntime/ # discovery, execution (leak-free), scheduling, streaming
├─ VeeMenu/ # ParsedOutput → NSMenu (colors, ANSI, SF Symbols, actions)
├─ VeeSearch/ # pure flatten + fuzzy-filter/rank of a plugin's menu tree
├─ VeePreferences/ # <xbar.var> stores + Keychain secrets
├─ VeeTrust/ # <vee.*> capability declarations → trust summaries
├─ VeeCatalog/ # xbar-plugins catalog client + installer
├─ VeeUI/ # SwiftUI settings + plugin-manager windows
├─ VeeApp/ # AppKit shell: status items, coordinators, app delegate
└─ vee/ # executable entry point
plugins/ # plugin SDKs (TypeScript/Python/Go), showcase plugins, shared fixtures
Contributions are welcome — see CONTRIBUTING.md. Vee is open source under the MIT License.






