Busabase
Busabase is an open-source (MIT) database and workspace for AI agents — data, docs, skills, and apps in one place. Run it locally, self-host it inside your network, or use Busabase Cloud, and turn age
翻译准备中
个人 GitHub 账号下公开仓库的所有者可以登录并验证所有权,自行管理介绍,无需管理员批准。
登录并生成验证文件,在 30 分钟内将其提交到此仓库的默认分支。其他分支或分叉仓库中的文件无效。然后在下方检查文件,即可无需管理员批准直接管理项目。请保留文件以维持管理权限。
如需登录,将前往登录页面。登录后请回到此处,再次点击所选的验证按钮。
在项目文件夹中运行 /nomorevibe verify,即可验证所有权并自行管理介绍。
一分钟完成验证Native Umami analytics for your macOS menu bar. Pure AppKit, multi-site insights, and light/dark appearance.
翻译准备中
正在加载完整 README。
查看完整 README ↗A lightweight macOS menu bar client for Umami. Keep multiple websites in one popover, track traffic changes, and open a site's details without leaving your workflow.
Built with AppKit, native drawing, URLSession, and macOS Keychain. The app does not embed WebKit or require a local web server. The HTML prototype is a separate design reference.
The documentation is available in English and Chinese. The current app interface is in Chinese; an in-app language switch is not implemented.
| Mode | Overview | Website details |
|---|---|---|
| Dark | ||
| Light |
Sample data.
| Component | Requirement |
|---|---|
| Intel Mac | Deployment target: macOS 10.15 Catalina or later |
| Apple Silicon Mac | Deployment target: macOS 11 or later |
| Build tools | Xcode with a macOS SDK and Swift 5.9 or later |
| Umami | A deployment supporting Bearer API key authentication |
The app uses Sparkle 2 for automatic update checks and manual checks in Settings → General → Check for Updates. In-app updates use signed, notarized tagged releases; CI builds are ad-hoc signed and are not updateable. Sparkle is the sole third-party Swift package dependency.
After the first release is published and its Cask update PR is merged:
brew tap helson-lin/umamibar https://github.com/helson-lin/umamibar
brew install --cask helson-lin/umamibar/umamibar
Upgrade with brew update, then brew upgrade --cask helson-lin/umamibar/umamibar. Homebrew's own legacy macOS support is separate from the app's deployment target. Older Macs can use the release ZIP directly.
Download the universal DMG from Releases, open it, and drag UmamiBar.app to Applications. Eject the disk image, then launch from Applications. Signed release builds support automatic Sparkle checks and manual checks in Settings → General → Check for Updates. Homebrew users update with the command above.
CI tests and packages the universal app on Intel and Apple Silicon for every branch push, pull request, and manual run. No tag is needed: open Actions → CI, select a successful run, and download either UmamiBar-macos-15 or UmamiBar-macos-15-intel from the summary (both contain a universal app; retained for 14 days; GitHub sign-in required). Extract the artifact, unzip the inner UmamiBar-<version>-universal.zip, and move UmamiBar.app to Applications. To package manually, select Run workflow and the desired branch.
Push a vX.Y.Z tag matching VERSION to publish the DMG, ZIP, SHA-256 checksums, signed Sparkle appcast, and generated Cask, then open a Cask update PR. See RELEASING.md for setup and release instructions.
Tagged releases require Developer ID signing, Apple notarization, and the SPARKLE_EDDSA_PRIVATE_KEY Actions secret; see release setup. Ordinary CI builds remain ad-hoc signed and unnotarized. Existing releases are unchanged.
From the repository root:
./scripts/build-app.sh
open dist/UmamiBar.app
The application bundle is generated at dist/UmamiBar.app. Copy it to your Applications folder if desired. It runs in the menu bar without a Dock icon.
For a local development build using only the host architecture:
./scripts/build-app.sh native
The native-only build uses the toolchain's default deployment target. Use the default universal build when checking the explicit legacy deployment targets.
Builds are ad-hoc signed for local development. They are not Developer ID signed or notarized. GitHub Actions can publish release ZIPs; application self-updating is not implemented.
When rebuilding, quit the running app (Settings → 通用) before opening the new bundle. Replacing the file does not replace an already-running process.
Settings live in a regular window rather than the popover, so it stays open while you switch to a browser to copy the API key.
| Deployment | Example | Behavior |
|---|---|---|
| Umami Cloud | https://api.umami.is/v1 | Uses the Cloud API base URL |
| Self-hosted, root deployment | https://analytics.example.com | Automatically adds /api |
| Self-hosted, subpath deployment | https://example.com/analytics/api | Uses the supplied path unchanged |
| Local development | http://localhost:3000 | Adds /api; local HTTP is allowed |
For regional Cloud endpoints or custom proxies, supply the full API base URL. Nonempty URL paths are preserved, so include the complete API path for subpath deployments.
Only HTTPS is accepted for remote services. HTTP is permitted for localhost, 127.0.0.1, and ::1. URLs containing credentials, query strings, or fragments are rejected. Redirects are refused to avoid forwarding credentials to another endpoint.
The app supports API keys, not username/password login. Compatibility with older self-hosted Umami versions depends on their available authentication and endpoints. See the official authentication guide and Cloud API key guide.
UmamiBar is available in English and Simplified Chinese. Choose System, 简体中文 or English under Settings → General → Language; the change applies immediately. System follows your macOS language, and any language other than Chinese falls back to English. UI strings live in Resources/<lang>.lproj/Localizable.strings, keyed by the Chinese source text passed to L("…"); tests-release/test_localization.py fails if a string is missing a translation.
General settings provide Launch at Login, language, menu bar display, and local data controls. The login switch reflects the system registration, including an approval-required state; macOS 13+ uses Apple's SMAppService. macOS 10.15–12 uses an app-specific user LaunchAgent. Enabling it keeps the app in the menu bar without opening a window. Registration must be checked from an installed app; the rendering harness never enables login startup.
Last successful data is saved by default under ~/Library/Application Support/UmamiBar/successful-data.json, separately for each service, website, period and timezone. A record contains a complete statistics/trend query and its original times, never the API key. Reopening restores matching results before a background refresh. Failed requests do not overwrite successful data; a missing range stays unavailable. Totals across mismatched query windows show “—”.
Open Saved Data to inspect retained ranges or clear them. Turning saving off asks for confirmation and clears stored statistics while keeping the connection and preferences. Already displayed live results can remain in memory. A source website that is unfollowed falls back to total visitors with a status message. Switching credentials clears saved results to avoid reusing another permission scope.
Each website displays visitors, change from the preceding period, a mini session chart, pageviews, bounce rate, and average duration. Hover a chart for bucket values. Click the chart or website name to open details.
The menu bar can show total visitors, visitors for a specific followed website, or just the icon. Icon-only mode uses the system square size; AppKit sizes numeric modes to their contents. Total mode sums visitors across selected websites for the active range. Visitors are not deduplicated across websites. It is not a live online-user count. Large numbers use compact suffixes; the tooltip retains the exact count.
Details retain the current time range and provide:
The return button restores the overview's scroll position. Escape also returns from details when handled by the panel's responder chain. Loading and failure states are separate from empty results; failed detail requests offer a retry button.
| Range | Window | Chart grouping |
|---|---|---|
| Last 24 hours | Rolling 24 hours | Hourly |
| Last 7 days | Rolling 168 hours | Daily |
| Last month | One calendar month before the query end | Daily |
“Last month” is neither the current calendar month nor a fixed 30-day window. The system time zone is used for grouping and labels. Partial buckets at the boundaries are retained.
The popover checks for stale data when opened and refreshes on a 60-second timer while visible. Regular polling pauses while closed. Manual refresh shows a spinner and a completion timestamp. Authentication and rate-limit failures pause automatic retries; use settings or manual refresh to recover. Website requests currently run sequentially, so a larger selection can take longer to refresh.
| Display | Source or calculation |
|---|---|
| Visitors | visitors from the stats endpoint; never calculated by adding chart buckets |
| Session trend | sessions from the pageviews endpoint; not a unique-visitor trend |
| Pageviews | pageviews from the stats endpoint |
| Bounce rate | bounces / visits × 100 |
| Average duration | totaltime / (visits - bounces), in seconds |
| Visitor change | Current visitors versus a separate query for the preceding interval of equal length |
| Breakdown percentages | Each row's count divided by the sum of the returned top five rows |
Missing fields or undefined denominators display —. A previous count of zero produces “New” or “Unchanged”, rather than an invalid percentage. A failed comparison query displays an unavailable comparison.
Successful time-series responses are expanded into complete time buckets; missing buckets become zero. The app handles Umami timezone-grouped SQL labels that serialize local wall-clock values with a Z suffix. Nonzero points entirely outside the requested range produce an error instead of a misleading empty chart. Backend timestamp conventions still need verification for other deployments.
Top-page and source counts follow the API's dimension semantics. The UI labels them as counts; top-five percentages are not whole-site percentages. Empty source results are displayed as empty results, not fabricated direct-traffic rows.
API references: summary statistics, time series, ranked metrics.
Run the test suite:
swift test --disable-sandbox \
--scratch-path /tmp/umamibar-build \
-Xswiftc -module-cache-path -Xswiftc /tmp/umamibar-module-cache
The tests cover URL validation, current and legacy stats responses, missing values, comparison calculations, month boundaries, sparse time series, and timezone-grouped labels. The temporary build paths avoid requiring access to user-level compiler caches. --disable-sandbox disables SwiftPM's build sandbox for this local build; it does not change application permissions.
For native rendering checks with sample data, compile the standalone harness:
xcrun swiftc -parse-as-library \
-module-cache-path /tmp/umamibar-module-cache \
Sources/UmamiBar/Models.swift \
Sources/UmamiBar/ChartView.swift \
Sources/UmamiBar/Components.swift \
Sources/UmamiBar/NativePanel.swift \
Sources/UmamiBar/API.swift \
Sources/UmamiBar/SettingsWindow.swift \
Sources/UmamiBar/SettingsViews.swift \
Sources/UmamiBar/Preferences.swift \
Sources/UmamiBar/SnapshotStore.swift \
Sources/UmamiBar/LoginLaunch.swift \
Sources/UmamiBar/TrafficAlerts.swift \
scripts/visual-check.swift \
-o /tmp/umamibar-native-check
/tmp/umamibar-native-check dark detail
/tmp/umamibar-native-check light empty
/tmp/umamibar-native-check dark settings-general
/tmp/umamibar-native-check dark detail --navigation-tests
For the isolated preference flow, start python3 scripts/mock-api.py --port 8768, then run /tmp/umamibar-native-check light settings-websites --mock=http://127.0.0.1:8768 --preferences-tests. Add --language-test when running from a test bundle containing the localization resources. --cached --pinned previews restored overview data. The harness uses isolated preferences and a temporary snapshot directory; login startup is never enabled by tests.
The harness requires a graphical macOS session. It writes PNG previews to /tmp/native-<appearance>-<screen>.png. Screens include overview, detail, empty, settings-connection, settings-websites, and settings-general. Setting UMAMIBAR_MOCK=http://127.0.0.1:PORT (a local server answering GET /api/websites for key test-key) drives the real verify → website list flow first; add --save-test to also check saving. --navigation-tests checks native action dispatch; it is not a full end-to-end network test.
An explicit --diagnose-series or --diagnose-details argument on the app executable performs read-only checks using the saved connection. These modes can access Keychain and contact your Umami server. They print counts and diagnostic status without printing keys, service URLs, website IDs, or page paths. Series diagnostics also print returned timestamps. They are optional debugging tools, not part of normal startup.
Sources/UmamiBar/
App.swift App lifecycle, menu bar, state and request coordination
Components.swift Shared painted design system: colors, surface, buttons, inputs
NativePanel.swift Popover screens: empty state, overview and details
SettingsWindow.swift Settings tabs and immediate persistence
SettingsViews.swift Native form rows and draggable website controls
Preferences.swift Menu display and connection-scoped website order
SnapshotStore.swift Atomic, scoped successful-result persistence
LoginLaunch.swift System login registration and older-macOS fallback
ChartView.swift Chart drawing, hover values and keyboard interactions
API.swift HTTP requests, authentication and website pagination
Models.swift API models, periods, metrics and URL normalization
TimeBuckets.swift Sparse-series expansion and timestamp handling
TrafficAlerts.swift Drop-to-zero and spike rules, alert de-duplication and notifications
Keychain.swift Credential storage
Diagnostics.swift Optional read-only API diagnostics
Tests/UmamiBarTests/ Core regression tests
scripts/ App packaging, icon generation and rendering checks
assets/ App icon master, iconset and ICNS
index.html Interactive design prototype with sample data
PRD.md Requirements and accepted changes
To view the prototype independently:
python3 -m http.server 8765 --bind 127.0.0.1
Open the local prototype. Its connection form does not save or transmit API keys. The native app does not depend on this server.
.app.See PRD.md for the requirements history. Checked-in images under docs/previews/ are sample-data snapshots and may lag small visual changes.
Suggested repository topics:
umami · macos · menu-bar · swift · appkit · analytics · privacy · macos-app
MIT © 2026 helson-lin