Repository navigation
Platforms and Signing
Nibtree ships for macOS today, as one universal app for Apple Silicon and Intel. This page explains how that app is built, how to turn on code signing and notarization, what is macOS only in the code, and what has to change to support Windows and Linux.
release.yml builds the app on macos-latest. It installs the Rust targets aarch64-apple-darwin and x86_64-apple-darwin, then runs tauri-action with --target universal-apple-darwin. Tauri builds the app once for each architecture and joins them into one binary, so a single download runs natively on every Mac. The .dmg and a compressed .app are attached to the GitHub release. The bundle targets (app and dmg) come from src-tauri/tauri.conf.json.
To build it yourself:
rustup target add aarch64-apple-darwin x86_64-apple-darwin
bun tauri build --target universal-apple-darwinFor everyday testing, bun tauri build --bundles app is faster: it builds only for your own Mac. Every pull request also gets the universal .dmg from macos-app.yml, which checks that the binary holds both architectures and that nibtree cli status answers, and keeps the .dmg under the run's Artifacts for 14 days.
Builds are unsigned by default. macOS then warns that the app is from an unidentified developer, and people have to allow it once (right-click the app and choose Open, or on recent macOS versions use System Settings, Privacy and Security, Open Anyway). Signing proves who built the app, and notarization means Apple has scanned it, so the warning goes away.
flowchart LR
Build["release.yml:<br/>tauri-action"] --> Q{"APPLE_* secrets set<br/>and env lines uncommented?"}
Q -->|"no"| Unsigned["unsigned app<br/>Gatekeeper warning"]
Q -->|"yes"| Sign["signed with the<br/>Developer ID certificate"]
Sign --> Notary["sent to Apple's<br/>notary service"]
Notary --> Signed["signed and notarized app<br/>opens without a warning"]
- Join the Apple Developer Program and create a Developer ID Application certificate. Export it with its private key as a
.p12file with a password. - Create an app-specific password for your Apple ID, and note your Team ID.
- In the repository, go to Settings, Secrets and variables, Actions, and add these six secrets (the same list is at the top of
release.yml):
| Secret | Value |
|---|---|
APPLE_CERTIFICATE |
the .p12 file, base64 encoded (base64 -i cert.p12) |
APPLE_CERTIFICATE_PASSWORD |
the password of the .p12
|
APPLE_SIGNING_IDENTITY |
the certificate name, like Developer ID Application: Name (TEAMID)
|
APPLE_ID |
the Apple ID email used for notarization |
APPLE_PASSWORD |
the app-specific password, not your real one |
APPLE_TEAM_ID |
your team ID |
- In
release.yml, uncomment the six matchingenvlines of the "Build and upload" step.
tauri-action reads these variables, signs the app and notarizes it. beta-publish.yml and stable-publish.yml pass secrets: inherit when they call release.yml, because a called workflow sees no secrets unless the caller hands them over.
Never commit a certificate, a .p12 file or a password, not even in a branch you plan to delete: git history keeps it. Secrets live only in GitHub's secret store. Delete the local .p12 once it is uploaded.
| Where | What | On other platforms |
|---|---|---|
src-tauri/src/memory.rs |
the memory readout, using macOS process APIs (proc_pid_rusage, the "responsible" process) |
Windows: the WebView2 processes and their private working set; Linux: a stub returns zero bytes, so the status bar hides the item |
src-tauri/src/git/cli.rs |
the git binary search (/opt/homebrew/bin/git, /usr/local/bin/git, /usr/bin/git) and the login shell PATH ($SHELL -l -c, default /bin/zsh) |
git on the app's own PATH, which Explorer fills, with no shell asked |
src/lib/stores/workspacePaths.ts and src-tauri/src/paths.rs
|
paths use / separators |
Windows paths leave Rust as C:/... (to_ui) and the page converts dialog paths (fromNativePath); comparisons are still case-sensitive |
src/lib/update/releases.ts |
parseReleases takes the first .dmg asset as the download |
needs a per-platform asset |
src-tauri/tauri.conf.json |
bundle targets app and dmg
|
tauri.windows.conf.json builds an NSIS installer; Linux needs targets |
.github/workflows/ci.yml, release.yml
|
the release build runs on macos-latest; CI also runs every check in the windows-frontend and windows-rust jobs |
build-windows in release.yml; Linux needs CI jobs |
scripts/*.sh |
bash demo scripts | need Git Bash or WSL on Windows |
| Keyboard shortcuts | Cmd (metaKey), usually with Ctrl too |
check each shortcut |
A few pieces are already ready: main.rs hides the console window on Windows release builds, child_process::hide_console starts git, gh and the clipboard reader without one (CREATE_NO_WINDOW), config::home_dir reads USERPROFILE first on Windows, os_info in commands/config.rs names the OS for bug reports on macOS, Linux and Windows (with platformName in releases.ts as the fallback), and tauri.conf.json already lists an icon.ico.
Windows-only code, the path rules and the console windows are covered in Windows Support.
For Linux, the Linuxbrew prefix is checked for Node and added to the fallback PATH of script runs.
Cross-platform builds are planned, not started. The rules until then, from CLAUDE.md, keep the door open:
-
Keep platform-specific code behind
cfgor runtime checks. Use#[cfg(target_os = "macos")]with a working fallback for other systems, likememory.rsdoes. Never let macOS-only code break the build elsewhere. -
Pick download assets per platform in
src/lib/update/releases.ts. The update check must offer a.dmgon macOS, a Windows installer on Windows and a Linux package on Linux. - Keep the web view in mind. Windows uses WebView2 (Chromium) and Linux uses WebKitGTK, so CSS and memory use will differ from WKWebView.
flowchart TB
subgraph Now["Today"]
M["macos-latest:<br/>CI and universal build"]
end
subgraph Next["Needed for Windows and Linux"]
Matrix["CI matrix:<br/>macOS, Windows, Linux"]
Deps["Linux: WebKitGTK and<br/>build packages on the runner"]
Bundles["bundle targets per platform"]
Assets["release.yml builds and attaches<br/>one asset per platform"]
Pick["releases.ts picks the asset<br/>for the running platform"]
Code["cfg fallbacks: git binary,<br/>PATH, paths, memory readout"]
end
Now --> Matrix
Matrix --> Deps
Matrix --> Code
Bundles --> Assets
Assets --> Pick
Concretely, the work is:
-
Backend: a Windows way to find git and its
PATH, path handling that accepts\and drive letters (and the\\?\form thatcanonicalizereturns on Windows), and memory readouts per platform or an honest "not available". -
Frontend: separator-aware path helpers with tests, a review of shortcuts (most accept Cmd or Ctrl already, but Ctrl+Minus for Back is a macOS habit), and per-platform assets in
releases.ts. -
CI: the
windows-frontendandwindows-rustjobs inci.ymlrun every check onwindows-latestand must pass like the macOS jobs. Linux needs the same onubuntu-latest. The Linux runner needs the WebKitGTK and build packages that Tauri lists as prerequisites. The one#[cfg(unix)]symlink incommands/tests.rsalready skips itself on Windows. -
Releases:
build-windowsinrelease.ymlruns when the repository variableWINDOWS_RELEASESistrue. Still to add: signing for Windows, and a Linux job.
-
Releases and CI for how
release.ymlis called. - How Updates Work for the update check that picks the download.
- How the Status Bar Works for the memory readout.
These pages are generated from docs/wiki. To correct something, open a pull request against the source file; edits made here are overwritten.
Using Nibtree
- Getting Started
- Welcome Screen
- Workspaces
- Files Panel
- File Operations
- File Icons
- Rounded Panels
- Editor and Tabs
- Pin Reorder and Wrap Tabs
- Single Tab Title
- Split Editor
- New File and Unsaved Changes
- Unload Hidden Tabs
- Editing Code
- Code Appearance
- Markdown Editor
- Image and PDF Preview
- Search Everywhere
- Recent Files
- Navigation Bar
- Find and Replace
- Changes and Commits
- Sign In Prompts
- Commit Box Layout
- Repository Actions
- Commit Options
- Ignoring Files
- Diffs
- Inline Diffs
- Staging View
- Revert a Change
- Resolving Conflicts
- Merge Tool
- Blame
- History and Log
- Merge Commits
- Branches and Tags
- Branches Popup
- Remotes
- Stashes
- Shelf
- Git Menu
- Git Dialogs
- Interactive Rebase
- Worktrees
- AI Agents
- AI Tasks
- AI Usage
- Keep Computer Awake
- Submodules
- Git LFS
- GitHub
- Git Console
- Terminal
- Terminal Features
- Scripts
- Navigation
- Menus
- Settings
- Settings Search
- Color Themes
- Settings Terminal and Automation
- Settings Files
- Updates
- Status Bar and Help
- Notifications
- Memory Use
- Clear Cache
- MCP and CLI
- Git Mergetool
- Keyboard Shortcuts
- Keyboard Shortcuts Editor
- Troubleshooting
- Troubleshooting Git
Developers
- Developer Guide
- Architecture
- Project Layout
- Backend
- How Folder Watching Works
- Folder Watching Bugs We Fixed
- How Workspace Files Work
- How the Preview Scheme Works
- Backend Services
- How Terminal Features Work
- Terminal Bugs We Fixed
- Frontend
- How the Rich Markdown Editor Works
- Rich Markdown Bugs We Fixed
- Git Menu Links
- Menu Keys and Routing
- Frontend Modules
- Blame Bugs We Fixed
- Project Color And Title Bar
- One Diff View
- Diff Bugs We Fixed
- Merge Tool Layouts
- Merge Tool Bugs We Fixed
- Color Theme Bugs We Fixed
- How the Connected Diff Works
- Rounded Panels Bugs We Fixed
- Update Bugs We Fixed
- Status Bar Bugs We Fixed
- MCP and CLI Bugs We Fixed
- Repository Actions Bugs We Fixed
- How the Changes Tab Works
- CodeMirror Patterns
- How the Cursor Works
- How Editor Features Work
- How the Path Bar Works
- Commands and Events
- Settings Reference
- Commands Workspace and Changes
- Commands Branches and Remotes
- Commands History and Extras
- Commands App and Tools
- Testing
- Test Suites
- Debugging
- Debugging with MCP
- Measuring Setting Memory
- How Terminal Memory Is Measured
- How Markdown Diagrams Work
- Releases and CI
- Publishing the Wiki
- Versioning and Changelog
- Browser Version Packages
- Browser Release Checks
- Docker Image
- Platforms and Signing
- Windows Support
- Windows Bugs We Fixed
- Windows MCP and CLI
- Docs and Screenshots
- UI Library
- UI Library MCP
- UI Library Bugs
- UI Library Migration
- Contributing
How features work
- Welcome screen
- Workspaces and folders
- Files panel
- File operations
- File icons
- Editor and tabs
- Pin, reorder and wrap tabs
- Single tab title
- Split editor
- New File and unsaved changes
- Unload hidden tabs
- Editing code
- Code appearance
- Markdown editor
- Image and PDF preview
- Search Everywhere
- Recent Files
- Navigation Bar
- Find and replace
- Changes and commits
- Sign-in prompts
- Commit box layout
- Repository actions
- Commit options
- Ignoring files
- Diffs
- Inline diffs
- Staging view
- Revert a change
- Resolving conflicts
- Merge tool
- Blame
- History and log
- Merge commits
- Commit tabs
- Branches and tags
- Branches popup
- Remotes
- Stashes
- Shelf
- Git menu
- Git dialogs
- Interactive rebase
- Worktrees
- AI agents
- AI usage
- Keep computer awake
- AI tasks
- Submodules
- Git LFS
- GitHub account
- Git Console
- Back and Forward
- Integrated terminal
- Scripts tool window
- Menu bar
- Settings
- Search in Settings
- Color themes
- Rounded panels
- Updates and release channels
- Status bar and help links
- Notifications
- Memory readout and memory log
- Clear Cache
- MCP server and command line tool
- git mergetool mode