{"id":13751789,"url":"https://github.com/project-gauntlet/gauntlet","last_synced_at":"2025-05-15T10:06:55.654Z","repository":{"id":219491740,"uuid":"746870424","full_name":"project-gauntlet/gauntlet","owner":"project-gauntlet","description":"Raycast-inspired open-source cross-platform application launcher with React-based plugins","archived":false,"fork":false,"pushed_at":"2025-05-05T17:52:31.000Z","size":4358,"stargazers_count":521,"open_issues_count":21,"forks_count":21,"subscribers_count":7,"default_branch":"main","last_synced_at":"2025-05-05T19:01:01.143Z","etag":null,"topics":["app-launcher","application-launcher","deno","iced","linux","macos","react","rust","typescript","windows"],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mpl-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/project-gauntlet.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2024-01-22T20:45:54.000Z","updated_at":"2025-05-05T17:52:34.000Z","dependencies_parsed_at":"2024-01-29T22:28:53.893Z","dependency_job_id":"b650f3ed-26b7-44db-974b-3d3efd0f9f63","html_url":"https://github.com/project-gauntlet/gauntlet","commit_stats":null,"previous_names":["project-gauntlet/gauntlet"],"tags_count":18,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/project-gauntlet%2Fgauntlet","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/project-gauntlet%2Fgauntlet/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/project-gauntlet%2Fgauntlet/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/project-gauntlet%2Fgauntlet/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/project-gauntlet","download_url":"https://codeload.github.com/project-gauntlet/gauntlet/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254319720,"owners_count":22051073,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["app-launcher","application-launcher","deno","iced","linux","macos","react","rust","typescript","windows"],"created_at":"2024-08-03T09:00:54.747Z","updated_at":"2025-05-15T10:06:50.636Z","avatar_url":"https://github.com/project-gauntlet.png","language":"Rust","readme":"# Gauntlet\n\n[![Discord](https://discord.com/api/guilds/1205606511603359785/widget.png?style=shield)](https://discord.gg/gFTqYUkBrW)\n\n\u003cimg align=\"right\" width=\"100\" height=\"100\" src=\"assets/linux/icon_256.png\"\u003e\n\nWeb-first cross-platform application launcher with React-based plugins\n\n\u003e [!WARNING]\n\u003e Launcher is being developed by single developer in their free time.\n\u003e Changes may be few and far between.\n\u003e\n\u003e There will probably be breaking changes which will be documented in [changelog](CHANGELOG.md).\n\n![image](https://github.com/user-attachments/assets/81339462-9cc3-469e-8cdc-ca74918bceab)\n\n## Demo\n\nhttps://github.com/user-attachments/assets/19964ed6-9cd9-48d4-9835-6be04de14b66\n\n## Features\n\n- Plugin-first\n    - Plugins are written in TypeScript\n    - Plugins can have the following functionality\n        - Create UI\n        - One-shot commands\n        - Dynamically provide list of one-shot commands\n        - Render quick \"inline\" content directly under main search bar based on value in it\n        - Get content from and add to Clipboard\n    - Plugins are distributed as separate branch in Git repository, meaning plugin distribution doesn't need any central\n      server\n    - Plugins IDs are just Git Repository URLs\n- Built-in functionality is provided by bundled plugin\n  - Applications: shows applications installed on the system in search results\n  - Calculator: shows result of mathematical operations directly under main search bar\n    - Includes converting currency using exchange rates\n    - Powered by [Numbat](https://github.com/sharkdp/numbat)\n  - Settings: open Gauntlet Settings\n  - More to come, see [#15](https://github.com/project-gauntlet/gauntlet/issues/15)\n- [React](https://github.com/facebook/react)-based UI for plugins\n    - Implemented using custom React Reconciler (no Electron)\n    - [iced-rs](https://github.com/iced-rs/iced) is used for UI\n- [Deno JavaScript Runtime](https://github.com/denoland/deno)\n    - Deno allows us to sandbox JavaScript code for better security\n    - Plugins are required to explicitly specify what permissions they need to work\n    - NodeJS is used to run plugin tooling, but as a plugin developer you will always write code that runs on Deno\n- Frecency-based search result ordering\n   - Frecency is a combination of frequency and recency\n   - More often the item is used the higher in the result list it will be, but items used a lot in the past will be ranked lower than items used the same amount of times recently\n   - Currently, there is no fuzzy matching. Results are matched per word by substring  \n- Designed with cross-platform in mind\n    - Permissions\n        - By default, plugins do not have access to host system\n        - If plugin asked for access to filesystem, env variables or running commands, it is required to specify\n          which operating systems it supports.\n        - If plugin doesn't use filesystem, env variables or running commands and just uses network and/or UI, it\n          is cross-platform\n    - Shortcuts\n        - Plugins are allowed to use only limited set of keys for shortcuts to support widest possible range of keyboards \n            - Only upper and lower-case letters, symbols and numbers\n        - Shortcut can have either `\"main\"` or `\"alternative\"` kind so plugins do not need to specify shortcut separately for each OS\n            - `\"main\"` shortcut requires following modifiers\n                - Windows and Linux: \u003ckbd\u003eCTRL\u003c/kbd\u003e\n                - macOS: \u003ckbd\u003eCMD\u003c/kbd\u003e\n            - `\"alternative\"` shortcut requires following modifiers\n                - Windows and Linux: \u003ckbd\u003eALT\u003c/kbd\u003e\n                - macOS: \u003ckbd\u003eOPT\u003c/kbd\u003e\n            - Whether \u003ckbd\u003eSHIFT\u003c/kbd\u003e is also required depends on character specified for shortcut, e.g `$` will\n              require \u003ckbd\u003eSHIFT\u003c/kbd\u003e to be pressed, while `4` will not\n\n##### OS Support\n\n##### Official\n- \u003cimg src=\"https://cdn.jsdelivr.net/gh/simple-icons/simple-icons@develop/icons/linux.svg\" width=\"18\" height=\"18\" /\u003e Linux X11\n   - Application plugin depends on `gtk-launch`\n- \u003cimg src=\"https://cdn.jsdelivr.net/gh/simple-icons/simple-icons@develop/icons/apple.svg\" width=\"18\" height=\"18\" /\u003e macOS M1\n\n##### Best-effort\n- \u003cimg src=\"https://cdn.jsdelivr.net/gh/simple-icons/simple-icons@develop/icons/linux.svg\" width=\"18\" height=\"18\" /\u003e Linux Wayland\n   - LayerShell support required\n   - Application plugin depends on `gtk-launch`\n- \u003cimg src=\"https://img.icons8.com/windows/32/windows-11.png\" width=\"18\" height=\"18\" /\u003e Windows\n- \u003cimg src=\"https://cdn.jsdelivr.net/gh/simple-icons/simple-icons@develop/icons/apple.svg\" width=\"18\" height=\"18\" /\u003e macOS Intel\n\n##### Planned features\n\n- See [#13](https://github.com/project-gauntlet/gauntlet/issues/13)\n- See [#15](https://github.com/project-gauntlet/gauntlet/issues/15)\n- See [#16](https://github.com/project-gauntlet/gauntlet/issues/16)\n\n##### Plugin APIs\n\n- UI\n  - Detail\n  - Form\n  - Action Panel\n  - List\n  - Grid\n  - Inline\n      - View directly under main search bar\n      - Requires separate permission to be explicitly specified in manifest because it reads everything user enters in main search bar\n- Stack-based Navigation\n- Assets\n  - Files placed into `assets` directory in root of plugin repository are accessible at plugin runtime using `assetData` function \n- Preferences\n  - Preferences defined in plugin manifest can be set by user and are accessible at plugin runtime using `pluginPreferences` and `entrypointPreferences` functions\n- Clipboard\n  - Accessible via `Clipboard` api\n  - Requires separate permission to be explicitly specified in manifest\n- HUD\n  - Shows small popup window with feedback information\n  - Accessible via `showHud` function\n- React Helper Hooks\n    - `usePromise`\n        - Helper to run promises in a context of React view\n        - Returns `AsyncState` object which contains `isLoading`, `error` and `data` properties\n    - `useStorage`\n        - Helper to store data between entrypoint, plugin and application runs\n        - Follows API similar to `useState` built-in React Hook\n        - Uses `localStorage` internally\n    - `useCache`\n        - Helper to store data between entrypoint runs but will be reset when plugin or application is restarted\n        - Follows API similar to `useState` built-in React Hook\n        - Uses `sessionStorage` internally\n    - `useCachedPromise`\n        - Helper to run promises with caching done automatically\n        - Follows `stale-while-revalidate` caching strategy\n        - Uses `usePromise` and `useCache` Hooks internally\n    - `useFetch`\n        - Helper to run `fetch()` with caching done automatically\n        - Follows `stale-while-revalidate` caching strategy\n        - Uses `useCachedPromise` Hook internally\n\n## Getting Started\n\n### Create your own plugin\n\n- Go to [plugin-template](https://github.com/project-gauntlet/plugin-template) and create your own GitHub repo from it.\n- Run `npm run dev` to start dev server (requires running application server)\n    - Dev server will automatically refresh the plugin on any file change\n- Do the changes you need\n    - You can configure plugin using [Plugin manifest](#plugin-manifest)\n    - Documentation is, at the moment, basically non-existent but TypeScript declarations in `@project-gauntlet/api`\n      and `@project-gauntlet/deno` should help\n    - For examples see [Dev Plugin](dev_plugin). It is very busy because it is used for Gauntlet development, but it has examples of pretty much every available API \n- Push changes to GitHub\n- Run `publish` GitHub Actions workflow to publish plugin to `gauntlet/release` branch\n- Profit!\n\n### Install plugin\n\nPlugins are installed in Settings UI. Use Git repository url of the plugin to install it. \n\n![](docs/settings_ui.png)\n\n### Install application\n\n#### macOS\n\nAlthough it is possible to install Gauntlet by using `.dmg` directly, application doesn't have auto-update functionality so it is recommended to install using `brew` package manager.\n\nBrew package: [link](https://formulae.brew.sh/cask/gauntlet)\n\nTo install run:\n```\nbrew install --cask gauntlet\n```\n\nTo start, manually open application.\n\n#### Windows\n\nDownload `.msi` at [Releases page](https://github.com/project-gauntlet/gauntlet/releases/latest) and open to install Gauntlet\n\nNote: application doesn't have auto-update functionality, and has to be updated manually\n\nTo start, manually open application.\n\n#### Arch Linux\n\nAUR package: [link](https://aur.archlinux.org/packages/gauntlet-bin)\n\nTo install run:\n```\nyay -S gauntlet-bin\n```\n\nTo start `systemd` service run: \n```\nsystemctl --user enable --now gauntlet.service\n```\n\n#### Nix\n\nThe nix flake in this repository is community maintained. If you face a problem, please create an issue and hopefully somebody will work on it.\n\nTo install, you either know what to do, or you can read more [here](nix/README.md).\n\n#### Other Linux Distributions\n\nAt the moment application is only available for Arch Linux and Nix. If you want to create a package for other distributions see [Application packaging for Linux](#application-packaging-for-Linux)\n\n### Global Shortcut\nMain window can be opened using global shortcut or CLI command:\n- Shortcut:\n    - Windows: \u003ckbd\u003eALT\u003c/kbd\u003e + \u003ckbd\u003eSpace\u003c/kbd\u003e\n    - Linux X11: \u003ckbd\u003eSuper\u003c/kbd\u003e + \u003ckbd\u003eSpace\u003c/kbd\u003e\n    - Linux Wayland: No global shortcut. Please use CLI command\n    - macOS: \u003ckbd\u003eCMD\u003c/kbd\u003e + \u003ckbd\u003eSpace\u003c/kbd\u003e\n    - Can be changed in Settings\n- CLI command:\n    - `gauntlet open`\n\n## Configuration\n\n### Plugin manifest\n\n```toml\n[gauntlet]\nname = 'Plugin Name'\ndescription = \"\"\"\nPlugin description\n\"\"\"\n\n[[preferences]] # plugin preference\nname = 'testBool'\ntype = 'enum' # available values: 'number', 'string,' 'bool', 'enum', 'list_of_strings', 'list_of_numbers', 'list_of_enums'\ndefault = 'item' # type of default depends on type field. Currently, list types have no default\ndescription = \"Some preference description\"\nenum_values = [{ label = 'Item', value = 'item'}] # defines list of available enum values, required for types \"enum\" and \"list_of_enums\"\n\n[[entrypoint]]\nid = 'ui-view' # id for entrypoint\nname = 'UI view' # name of entrypoint\npath = 'src/ui-view.tsx' # path to file, default export is expected to be function React Function Component\nicon = 'icon.png' # optional, path to file inside assets dir\ntype = 'view'\ndescription = 'Some entrypoint description'\n\n[[entrypoint.preferences]] # entrypoint preference\nname = 'boolPreference'\ntype = 'bool'\ndefault = true\ndescription = \"bool preference description\"\n\n[[entrypoint.actions]]\nid = 'someAction' # id of action, needs to align with value in \u003cAction\u003e \"id\" property\ndescription = \"demo action description\"\nshortcut = { key = ':', kind = 'main'} # key string only accepts lower and upper-case letters, numbers and symbols. kind can be \"main\" or \"alternative\"\n\n[[entrypoint]]\nid = 'command-a' \nname = 'Command A'\npath = 'src/command-a.ts' # path to file, the whole file is a js script\ntype = 'command'\ndescription = 'Some entrypoint description'\n\n[[entrypoint]]\nid = 'entrypoint-generator'\nname = 'Entrypoint generator'\npath = 'src/entrypoint-generator.ts'\ntype = 'entrypoint-generator'\ndescription = 'Some entrypoint description'\n\n[[entrypoint]]\nid = 'inline-view'\nname = 'Inline view'\npath = 'src/inline-view.tsx'\ntype = 'inline-view'\ndescription = 'Some entrypoint description'\n\n[permissions]\nnetwork = [\"github.com\", \"example.com:8833\"]\nclipboard = [\"read\", \"write\", \"clear\"]\nmain_search_bar = [\"read\"]\n\n# if specified requires supported_system to be specified as well\nenvironment = [\"ENV_VAR_NAME\"] \n\n# if specified requires supported_system to be specified as well\nsystem = [\"apiName\"]\n\n# if specified requires supported_system to be specified as well\n[permissions.filesystem]\nread = [\n    \"C:\\\\ProgramFiles\\\\test\",\n    \"C:/ProgramFiles/test\",\n    \"{windows:user-home}\\\\test\",\n    \"{windows:user-home}/test\",\n    \"{linux:user-home}/test\",\n    \"/etc/test\"\n]\nwrite = [\"/home/exidex/.test\"]\n\n# if specified requires supported_system to be specified as well\n[permissions.exec]\ncommand = [\"ls\"]\nexecutable = [\"/usr/bin/ls\"]\n\n[[supported_system]]\nos = 'linux' # 'linux', 'windows' or 'macos'\n\n```\n\n### Application config\n\nLocated at `$XDG_CONFIG_HOME/gauntlet/config.toml` for Linux. Not used at the moment.\n\n## CLI\n\n### Application\n\nThe Application has a simple command line interface\n\n- `gauntlet` - starts server\n  - `gauntlet --minimized` - starts server without opening main window \n- `gauntlet open` - opens application window, can be used instead of global shortcut\n- `gauntlet settings` - settings, plugin installation and removal, preferences, etc\n\n### Dev Tools\n\n[`@project-gauntlet/tools`](https://www.npmjs.com/package/@project-gauntlet/tools) contains separate CLI tool for plugin\ndevelopment purposes. It has following commands:\n\n- `gauntlet dev`\n    - Starts development server which will automatically refreshed plugin on any file change.\n- `gauntlet build`\n    - Builds plugin\n- `gauntlet publish`\n    - Publishes plugin to separate git branch. Includes `build`\n    - `publish` assumes some things about git repository, so it is recommended to publish plugin from GitHub Actions\n      workflow\n\n[Plugin template](https://github.com/project-gauntlet/plugin-template) has nice `npm run` wrappers for them.\n\n## Theming\n\nSee [THEME.md](./docs/THEME.md)\n\n## Architecture\n\nThe Application consists of 4 parts: server, frontend, plugin runtime and settings.\nEach plugin runs in separate plugin runtime in separate OS process. Each plugin is its own sandboxed Deno Worker.\nIn plugin manifest it is possible to configure permissions which will allow plugin to have access to filesystem,\nnetwork, environment variables or subprocess execution.\nServer saves plugins themselves and state of plugins into SQLite database.\n\nFrontend is GUI module that uses [iced-rs](https://github.com/iced-rs/iced) as a GUI framework. It is run in the same process as a server.\n\nPlugins can create UI using [React](https://github.com/facebook/react).\nPlugin Runtime implements custom React Reconciler (similar to React Native) which renders GUI components to frontend.\nPlugin Runtime listens on signals from frontend, so when user opens view defined by plugin, frontend sends an open-view request.\nPlugin Runtime then receives it, runs React render and React Reconciler makes requests to the frontend containing information what actually should be rendered.\nWhen a user interacts with the UI by clicking button or entering text into form,\nfrontend sends events to server to see whether any re-renders are needed.\n\nSettings is a GUI application runs in separate process that communicates with server using a simple request-response approach.\n\nSimplified communication:\n![](docs/architecture.png)\n\nComponents:\n![](docs/architecture-blocks.png)\n\nPlugins (or rather its compiled state: manifest, js code and assets) are distributed via Git repository in `gauntlet/release` branch (similar to GitHub Pages).\nWhich means there is no one central place required for plugin distribution.\nAnd to install plugin all you need is Git repository url.\n\n## Application packaging for Linux\n\nThis section contains a list of things\nthat could be useful for someone who wants to package application for Linux distribution.\nIf something is missing, please [create an issue](https://github.com/project-gauntlet/gauntlet/issues).\n\nApplication is already packaged for [Arch Linux](#arch-linux) and [Nix](#nix) so you can use them as examples.\n\nRelevant CLI commands:\n\n- `$ gauntlet --minimized`\n    - Server needs to be started when user logs in, e.g. using `systemd` service\n- `$ gauntlet open`\n    - Main windows is usually opened using [global shortcut](#global-shortcut), this CLI command can be used in cases where global shortcut functionality is not available \n- `$ gauntlet settings`\n    - Settings are usually started on demand from Gauntlet itself\n\n`.desktop` sample file can be found [here](assets/linux/gauntlet.desktop)\n\n`systemd` service sample file can be found [here](assets/linux/gauntlet.service)\n\n###### Directories used\n\n- data dir - `$XDG_DATA_HOME/gauntlet` or `$HOME/.local/share/gauntlet`\n    - contains application state `data.db`\n- cache dir - `$XDG_CACHE_HOME/gauntlet` or `$HOME/.cache/gauntlet`\n    - contains icon cache\n- config dir - `$XDG_CONFIG_HOME/gauntlet` or `$HOME/.config/gauntlet`\n    - contains application config `config.toml`\n    - application will never do changes to config file\n- state dir - `$XDG_STATE_HOME/gauntlet` or `$HOME/.local/state/gauntlet`\n    - contains log files created by plugin development \n- `.desktop` files at locations defined by [Desktop Entry Specification](https://specifications.freedesktop.org/desktop-entry-spec/desktop-entry-spec-latest.html)\n\nClient and Setting applications have GUI and therefore use all the usual graphics-related stuff from X11.\nWayland support requires LayerShell protocol `zwlr_layer_shell_v1`.\n\n## Building Gauntlet\nYou will need:\n- NodeJS\n- Rust\n- Protobuf Compiler\n- CMake (not used by the project itself, but is required by a dependency)\n- On Linux: `libxkbcommon-dev` (note: name may differ depending on used distribution)\n\nTo build dev run:\n```bash\nnpm ci\nnpm run build\nnpm run build-dev-plugin\ncargo build\n```\nIn dev (without \"release\" feature) application will use only directories inside project directory to store state or cache.\n\nTo build release run:\n```bash\nnpm ci\nnpm run build\ncargo build --release --features release\n```\nBut the new version release needs to be done via GitHub Actions\n\n## Contributing\n\nIf you'd like to help build Gauntlet you can do it in more ways than just contributing code:\n- Reporting a bug or UI/UX problem\n- Creating a plugin\n\nIf you are looking for things to do see pinned [issues](https://github.com/project-gauntlet/gauntlet/issues).\n\nFor simple problems feel free to open an issue or PR and tackle it yourself!\n\nFor more significant changes please contact creators on Discord (invite link on top of README) and discuss first.\n\nAll and any contributions are welcome.\n\n## Versioning\n\n### Application\n\nApplication uses simple incremental integers starting from `1`.\nIt doesn't follow the SemVer versioning.\nGiven application's reliance on plugins, once it is stable,\nintroducing breaking changes will be done carefully (if at all) and will be given a reasonable grace period to migrate.\nSemVer is about a hard cutoff between major versions with breaking changes, which doesn't fit this kind of application.\nBefore application is declared stable, breaking changes could be done without a grace period.\n\n### Tools\n\n[`@project-gauntlet/tools`](https://www.npmjs.com/package/@project-gauntlet/tools) uses SemVer.\n\n### Plugins\n\nPlugins only have the latest published \"version\". \n","funding_links":[],"categories":["Rust","Application Launcher","Useful"],"sub_categories":["Utilities"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fproject-gauntlet%2Fgauntlet","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fproject-gauntlet%2Fgauntlet","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fproject-gauntlet%2Fgauntlet/lists"}