CLI tool
ospfranco/sol avatar
ospfranco/sol

Sol runs natively on a React Native macOS build, and its reset script names exactly two permissions

MacOS launcher & command palette

3,156 stars186 forksTypeScriptMIT

At a glance

What is it?
ospfranco/sol is a MIT licensed macOS launcher and command palette with twenty-six listed features, built as a React Native macOS application with a CocoaPods layer. It is installed with a Homebrew cask, and the repository carries its built application inside a committed releases directory as well as in GitHub releases.
Who is it for?
Sol suits someone who wants a launcher that also does calendar, clipboard, and small scripting work without leaving the keyboard, and the Homebrew cask makes the install a single line. Two things to know before you use it.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 16 days ago.
What is it written in?
Mainly TypeScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 5, 2026, and from our analysis. They are not legal advice.

Editorial analysis

Runs natively means a React Native macOS build with a CocoaPods layer

The opening description calls Sol an open source app launcher focused on ease of use and speed, and says it has minimal configuration and runs natively.

Then the contributing section says you need to set up your machine for macOS development with React Native, and lists Mise, Xcode, and Cocoapods as the things to install, with a pointer to any online tutorial for iOS and macOS React Native setup.

Those two statements describe different things. Native in this context means a real macOS application rather than a web page in a window, which is true of a React Native macOS build. It does not mean an AppKit or Swift binary, and the manifest settles the question: `react-native` and `react-native-macos` are both runtime dependencies, with Metro and Babel configured at the root, a `macos/` directory holding the native project, and `nativewind` plus a Tailwind configuration doing the styling.

There is also a Ruby layer. The repository carries a `Gemfile` and a `Gemfile.lock`, a `fastlane/` directory, and a pods script that changes into the macos directory, removes `Podfile.lock`, runs `bundle exec pod install`, and then resolves packages through xcodebuild against the `sol.xcworkspace` scheme.

So the deliverable is a native macOS app whose interface is written in TypeScript and React Native, built on CocoaPods.

The permissions reset script names Calendar and Accessibility and nothing else

One script in the manifest is the most informative line in the repository, because it names exactly what the application asks the operating system for:

code
"permissions:reset": "tccutil reset Calendar com.ospfranco.sol && tccutil reset Accessibility com.ospfranco.sol",

Two permission classes, Calendar and Accessibility, against the bundle identifier `com.ospfranco.sol`. Nothing else appears in the command, which tells you the app's TCC surface is two classes rather than a long list.

Both are explainable from the feature list. Showing the upcoming appointment in the menu bar requires Calendar. A window manager and custom keyboard shortcuts require Accessibility, since that is the class macOS uses for synthetic events and window manipulation.

The script exists because those two prompts are the ones that get stuck. macOS will not re-prompt for a permission the user denied once, so a denied Calendar prompt means the menu bar item stays empty with no obvious path back except revoking the grant, which is exactly what `tccutil reset` does.

The features around them raise the surface worth thinking about. There is a clipboard manager, browser bookmark import, a script runner, custom AppleScript commands, and a command that retrieves the Wi-Fi password. Each of those is local to the machine, and each is also reachable from a launcher where a single keystroke starts the action.

The built application is committed to the repository and also published as a release

The README tells manual installers to download the latest build from the repository tree, with the link pointing at `tree/main/releases`.

`releases/` is a directory in the working tree. So the built application is versioned in the repository alongside the source.

There are also three GitHub releases, numbered 2.1.362, 2.1.361, and 2.1.359, which is what the release badge at the top links to. So the same artefact class exists in two places: committed files under `releases/` on the main branch, and tagged releases.

The build scripts confirm the committed copy is a working artefact rather than a leftover. The dev script removes it before launching:

code
"dev": "bundle exec fastlane dev && rimraf releases/Sol.app && open /Applications/Sol.app",

It deletes `releases/Sol.app`, runs the fastlane development build, and opens the installed application from `/Applications`. So the development loop writes a bundle into the repository, deletes it, and runs the one in Applications instead.

A committed `Header.jpg` sits at the root as well, which is the kind of file that belongs to the bundle rather than to the code.

Three toolchains, and the documented setup needs an experimental flag

The build instructions are short, and each line names a different tool:

code
mise plugin add cocoapods
# To enable hooks
mise settings experimental=true
# Will install all bun, ruby and run the installation of dependencies
mise install

# You can then run the app with
bun macos

Three package managers are involved. `mise install` sets up bun and ruby and runs the dependency installation. The JavaScript dependencies are locked in `bun.lock`, and the Ruby ones in `Gemfile.lock`, with fastlane and CocoaPods both invoked through bundler.

The `macos` script the last line runs is `react-native run-macos --scheme debug`. So `bun macos` is not a separate command; it is the package script executed by bun.

The line worth pausing on is `mise settings experimental=true`, commented in the file as being needed to enable hooks. The documented onboarding path for this project requires turning on an experimental feature of the tool that manages the toolchain.

Everything else is delegated: the instructions say to follow any online tutorial for setting up a machine for iOS and macOS React Native development, rather than specifying versions of Xcode, CocoaPods, or the Ruby that CocoaPods needs. For a project with a `typecheck` script and a `mise.toml` at the root, the floor is left to the reader.

Prettier and Biome are both configured at the root

The repository carries `.prettierrc`, `biome.json`, and `@biomejs/biome` at a pinned version in the development dependencies.

Both formatters are configured for the same codebase. There is a `format` script convention referenced by Biome's presence, a `lint` path implied by the same, a `typecheck` script running `tsc --noEmit`, and a `fix-dependencies` script that runs `rnx-align-deps --write`.

This is the same pattern that appears across projects that grew over years with a formatter, changed formatters, and kept the old configuration rather than deleting it. Two formatters disagreeing over the same file is a small daily friction and a real one when a contributor does not know which one a pre-commit step runs.

The tree also carries `patches/` for patching dependencies and a `scripts/` directory holding the version bump script that the `bump` script invokes. `app.json`, `babel.config.js`, `metro.config.js`, and `nativewind-env.d.ts` complete the React Native configuration set, and `index.js` at the root is the entry point.

So a contributor to this project needs a Ruby toolchain, a JavaScript toolchain, and a React Native configuration, and two formatters.

Version numbers skip a build and the newest tag shares a minute with the last push

The three most recent releases are numbered 2.1.362, 2.1.361, and 2.1.359.

Two observations. The sequence skips 2.1.360, so a build number was consumed without a release, which is what happens when a version is bumped and the build fails before the tag is pushed. And the numbering is three-part with a build-like third component rather than a semver patch, which is consistent with a continuous-integration counter.

The dates run 2026-09-20, 2026-09-18, and 2026-09-15, so three releases in five days. The manifest version is 2.1.362, matching the newest tag exactly.

The last push to the main branch was on 2026-09-20 at 01:19:04 UTC. The 2.1.362 release was published at 01:18:48 the same night, sixteen seconds earlier. So the tag was created first and the commit landed immediately after it, which is the order you would expect from a release step that commits its own version bump.

The `bump` script is a shell script under `scripts/`, so the version is maintained by a script rather than by a release tool reading the manifest.

Twenty-six features, one misspelled, one beta library pinned in runtime dependencies

The feature list has twenty-six entries, from app search and custom shortcuts through a clipboard manager, a notes scratchpad, a script runner, and symbolic link support.

One of them is misspelled in the file: the menu bar entry reads Show upcoming appointement in Menu Bar.

The dependencies line up with the list in a way that makes it readable. `fuse.js` and `minisearch` are both there, so fuzzy search has two implementations available. `nanoid` and `uuid` cover two of the three generators, and `chance` covers the third. `expr-eval` and `convert-units` are the math evaluator. `chrono-node` and `luxon` are the date handling behind the calendar entries.

Two entries deserve a second look in a runtime dependency list. `@legendapp/list` is pinned to the exact version `3.0.0-beta.53`, a beta release, in dependencies rather than in development dependencies. And `@sentry/react-native` is a runtime dependency, so the application ships crash reporting.

For a launcher whose feature list includes a clipboard manager, bookmark import, a script runner, and retrieving the Wi-Fi password, having a reporting service in the runtime dependencies is a data-flow fact worth knowing, alongside the two macOS permission classes the reset script names.

Editorial conclusion

Sol suits someone who wants a launcher that also does calendar, clipboard, and small scripting work without leaving the keyboard, and the Homebrew cask makes the install a single line. Two things to know before you use it. It is a React Native application rather than a native one, so the feature list is delivered through a JavaScript UI on top of a macOS pod layer, and the development setup needs Mise, Xcode, and CocoaPods rather than a single toolchain. And it asks for Calendar and Accessibility permissions, which the repository is explicit about, so decide what you are handing access to before you grant the first prompt.

Frequently asked questions

What is Sol and how do I install it?

Sol is a MIT licensed open source macOS app launcher and command palette, installed with brew install --cask sol. Manual downloads are also offered from the releases directory on the main branch. It needs macOS and has no separate Linux or Windows build.

What can Sol do?

Twenty-six listed features including app search, custom shortcuts, Google translate, a calendar with the next appointment in the menu bar, custom AppleScript commands, browser bookmark import, a window manager, an emoji picker, a clipboard manager, a notes scratchpad, retrieving the Wi-Fi password, showing the IP address, switching the OS theme, a process killer, NanoID and UUID generation, sample paragraph text, formatting and pasting JSON, forwarding media keys to Spotify or Apple Music, hiding menu bar items, evaluating math, a script runner, and symbolic link support.

What macOS permissions does Sol ask for?

The manifest ships a permissions:reset script that names two permission classes, Calendar and Accessibility, against the bundle identifier com.ospfranco.sol. The calendar menu bar entry needs the first and the window manager and custom shortcuts need the second. The script exists to clear a denied prompt so it can be granted again.

What do I need to build Sol from source?

A machine set up for macOS React Native development: Mise, Xcode, and Cocoapods, plus bun and ruby which mise install sets up. The documented commands add the cocoapods plugin, run mise settings experimental=true to enable hooks, run mise install, then run the app with bun macos.

Is Sol a native macOS app?

It is a native macOS application built with React Native, not a Swift or AppKit one. The manifest depends on react-native and react-native-macos, the repository carries a macos directory with CocoaPods and fastlane, and styling uses nativewind with Tailwind.

Official sources

  1. Issues
  2. License: MIT
  3. ospfranco/sol on GitHub
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/ospfranco-sol.svg)](https://hysenlabs.com/projects/ospfranco-sol)