gauntlet
gauntlet copied to clipboard
Raycast-inspired application launcher with React-based plugins
Gauntlet
~~Web-first~~ (not yet) ~~cross-platform~~ (not yet) application launcher with React-based plugins.
[!NOTE] This is an MVP, expect bugs, missing features, incomplete ux, etc.
At the moment, it is not yet ready for daily usage.
There will probably be breaking changes which will be documented in changelog.

Features
- Plugin-first
- Plugins can create UI or one-shot commands
- It is just a framework for plugins
- No plugins are provided by default
- Plugins are distributed as separate branch in git repository (similar to how GitHub Pages work)
- Plugins are installed using Git Repository URL
- React-based UI for plugins
- Implemented using custom React Reconciler
- iced-rs is used for UI
- It is even possible to have multiple frontend implementations
- Deno JavaScript Runtime
- Deno allows us to sandbox JavaScript code for better security
- Plugins are required to explicitly specify what permissions they need to work
- Node is still used to run tooling
- Client-Server architecture
- All plugins run on server and render UI to a separate client process
- On Linux, DBus is used for inter-proces communication
- Designed with cross-platform in mind
- Permissions
- If plugin asked for access to filesystem, env variables, FFI or running commands, it is required to specify which operating systems it supports.
- If plugin doesn't use filesystem, env variables, ffi or running commands and just uses network and/or UI, it is cross-platform
- Keybinds (not yet implemented)
- Keybind is "primary" or "secondary" + key
- Meaning of "primary" and "secondary" depends on operating system that plugin is running on.
- E.g. for Linux "primary" is Ctrl, "secondary" - Alt
- But for macOS "primary" is Cmd, "secondary" - Opt
- Permissions
OS Support
Implemented
Linux
Planned
Windows
macOS
UI
Implemented
- Detail
- Form
- Action Panel
- Separate settings view
Planned
- View router
- List
- Grid
- Toast popups
- Keyboard only navigation
- Theming
- Themable icons
- Vim motions
APIs
Planned
- Clipboard
- Preferences
- Local Storage
- OAuth PKCE flow support
- Search bar parsing
Getting Started
Create your own plugin
- Go to plugin-template and create your own GitHub repo from it.
- Run
npm run devto start dev server (requires running application server)- Dev server will automatically refresh the plugin on any file change
- Do the changes you need
- You can configure plugin using Plugin manifest
- Documentation is, at the moment, basically non-existent but TypeScript declarations in
@project-gauntlet/apiand@project-gauntlet/denoshould help - See Dev Plugin for examples
- Push changes to GitHub
- Run
publishGitHub Actions workflow to publish plugin to release branch - Profit!
Install plugin
Plugins are installed in Settings UI. Use Git repository name of the plugin to install it.

Install application
[!NOTE] At the moment application is not published anywhere, so you have to download it from the GitHub Releases
Be the first one to create a package. See Application packaging for Linux
Configuration
Plugin manifest
[gauntlet]
name = 'Plugin Name'
[[entrypoint]]
id = 'ui-view' # id for entrypoint
name = 'UI view' # name of entrypoint
path = 'src/ui-view.tsx' # path to file, default export is expected to be function React Function Component
type = 'view'
[[entrypoint]]
id = 'command-a'
name = 'Command A'
path = 'src/command-a.ts' # path to file, the whole file is a js script
type = 'command'
[permissions] # For allowed values see: https://docs.deno.com/runtime/manual/basics/permissions
environment = ["ENV_VAR_NAME"] # array of strings, if specified requires supported_system to be specified as well
high_resolution_time = false # boolean
network = ["github.com"] # array of strings
ffi = ["path/to/dynamic/lib"] # array of strings, if specified requires supported_system to be specified as well
fs_read_access = ["path/to/something"] # array of strings, if specified requires supported_system to be specified as well
fs_write_access = ["path/to/something"] # array of strings, if specified requires supported_system to be specified as well
run_subprocess = ["program"] # array of strings, if specified requires supported_system to be specified as well
system = ["apiName"] # array of strings, if specified requires supported_system to be specified as well
[[supported_system]]
os = 'linux' # currently only 'linux'
Application config
Located at $XDG_CONFIG_HOME/gauntlet/config.toml for Linux. Not used at the moment.
CLI
Application
The Application has a simple command line interface
gauntlet server- server part of launchergauntlet client- gui part of launchergauntlet management- settings, plugin installation, etc
Dev Tools
@project-gauntlet/tools contains separate CLI tool for plugin
development purposes. It has following commands:
gauntlet dev- Starts development server which will automatically refreshed plugin on any file change.
gauntlet build- Builds plugin
gauntlet publish- Publishes plugin to separate git branch. Includes
build publishassumes some things about git repository, so it is recommended to publish plugin from GitHub Actions workflow
- Publishes plugin to separate git branch. Includes
Plugin template has nice npm run wrappers for them.
Architecture
The Application consists of three parts: server, frontend and settings. Server is an application that is registered on session dbus with a well-known name and exposes 2 dbus interfaces: one for frontend, other for settings application. All plugins run on server. Each plugin in its own sandboxed Deno Worker. In plugin manifest it is possible to configure permissions which will allow plugin to have access to filesystem, network, environment variables, ffi or subprocess execution. Server saves plugins and state of plugins into SQLite database.
Frontend is GUI application that uses iced-rs as a GUI framework. It is also registered on session dbus with well-known name and exposes one dbus interface for server to call. From the perspective of dbus, it can also be considered a "server" because it answers requests that come from server.
Plugins can create UI using React. Server implements custom React Reconciler (similar to React Native) and renders to frontend running as a separate process. Server listens on signals from frontend, so when user opens view defined by plugin, frontend sends an open-view signal. Server then receives the signal, runs React render and React Reconciler makes requests to the frontend containing information what actually should be rendered. When a user interacts with the UI by clicking button or entering text into form, frontend sends signals to server to see whether any re-renders are needed.
Settings is also a GUI application that communicates with server via DBus using a simple request-response approach.

Plugins (or rather its compiled state) are distributed via Git repository in release branch (similar to GitHub Pages).
Which means there is no one central place for plugin distribution.
And to install plugin all you need is Git repository url.
Application defines set of React components to use for plugins.
Creating and validating components involves some boilerplate.
Component model was created for help manage is.
It is essentially a json file which defines what components exist, what properties and event handler they have.
This file is then used
to generate TypeScript typings for @project-gauntlet/api and Rust validation code for server and frontend.
Application packaging for Linux
This section contains a list of things that could be useful to someone who wants to package application for Linux distribution. If something is missing, please create an issue.
Gauntlet executable consists of three applications:
$ path/to/gauntlet/executable server- Needs to be started when user logs in
$ path/to/gauntlet/executable client- Started on demand using Super key (or any other key/shortcut depending on your preference)
$ path/to/gauntlet/executable management- Started on demand from the list of available applications (will vary depending on desktop environment or windows manager chosen)
Client and Settings applications expect Server to always be running. Recommended way of ensuring that is running Server as Systemd service. Communication is done via DBus session bus.
Directories used
- data dir -
$XDG_DATA_HOME/gauntletor$HOME/.local/share/gauntlet- contains application state
data.db
- contains application state
- config dir -
$XDG_CONFIG_HOME/gauntletor$HOME/.config/gauntlet- contains application config
config.toml - application will never do changes to config file
- contains application config
Application and Dev Tools use temporary directories:
- Rust: tempfile crate
- JS: NodeJS mkdtemp
Client and Setting applications have GUI and therefore use all the usual graphics-related stuff from Wayland or X11. For Wayland currently no special protocols are required, but it may change in the future.
Building Gauntlet
You will need:
- NodeJS v18
- Rust
- Protobuf Compiler
To build run:
npm run build
cargo build
Versioning
Application
Application uses simple incremental integers starting from 1.
It doesn't follow the SemVer versioning.
Given application's reliance on plugins, once it is stable,
introducing breaking changes will be done carefully (if at all) and will be given a reasonable grace period to migrate.
SemVer is about a hard cutoff between major versions with breaking changes, which doesn't fit this kind of application.
Before application is declared stable, breaking changes could be done without a grace period.
Tools
@project-gauntlet/tools uses SemVer.
Plugins
Plugins only have the latest published "version".
