Skip to content

chmouel/raffi

Repository files navigation

Raffi Application Launcher

Raffi is an application launcher designed to sit on top of Fuzzel, or, if preferred, operate using its own built‑in interface. It allows commands and scripts to be defined in a YAML configuration file, with support for icons, arguments, conditional visibility, and script execution through configurable interpreters.

image

See more screenshots below

Installation

Prebuilt binaries are available from the GitHub releases page. Download the archive or package suitable for your platform. If you intend to use the default interface, Fuzzel must also be installed.

On Arch Linux, Raffi can be installed from the AUR using a helper such as:

yay -S raffi-bin

On NixOS or using Nix (unstable channel):

nix-shell -p raffi

With LinuxBrew or Homebrew:

brew tap chmouel/raffi https://github.com/chmouel/raffi
brew install raffi

From crates.io:

cargo install raffi

To build from source:

git clone https://github.com/chmouel/raffi.git
cd raffi
cargo build --release

If you only require Fuzzel integration and want a significantly smaller binary, build without the native UI:

cargo build --release --no-default-features

This reduces the binary from roughly 15 MB to around 1.1 MB by removing the iced GUI dependency.

Usage

Running raffi launches configured entries through the selected interface. The chosen item is executed according to the configuration.

Common options include:

-p or --print-only prints the command rather than executing it. -c or --configfile <FILE> selects a custom configuration file. -r or --refresh-cache refreshes cached icon paths. -I or --disable-icons disables icons for slightly faster startup. -u or --ui-type <TYPE> selects fuzzel or native (default is fuzzel). -i or --initial-query <QUERY> pre-fills the search field on launch (native mode only). -t or --theme <THEME> selects dark or light theme (default is dark, native mode only). --default-script-shell <SHELL> sets the default interpreter for scripts.

Window Manager Integration

Sway

set $menu raffi -p
set $super Mod4
bindsym $super+Space exec $menu | xargs swaymsg exec --

Hyprland

$super = SUPER
bind = $super, R, exec, (val=$(raffi -pI); echo $val | grep -q . && hyprctl dispatch exec "$val")

User Interfaces

Raffi supports two interface modes.

Fuzzel mode uses the external Fuzzel launcher and integrates naturally with Wayland environments.

Native mode uses an internal iced‑based graphical interface with fuzzy search, keyboard navigation, and theme support (dark by default, light available via -t light or config). It is suitable if you prefer a self‑contained graphical window.

Native Interface Extras

Calculator

The native interface includes a built‑in calculator which evaluates expressions as you type. Standard mathematical operators are supported, along with functions such as sqrt, sin, cos, tan, log, ln, exp, abs, floor, and ceil. Results can be copied to the clipboard using Enter, provided wl-copy is available.

Currency Converter

The native interface also includes a currency converter. Enter an amount prefixed with the configured trigger (default $) followed by a target currency. Exchange rates are fetched from the Frankfurter API and cached for one hour.

Example inputs:

$10 to eur
$50 gbp to usd
$100eur to jpy
€10 to usd    (with trigger set to €)

Dynamic Script Filters

The native interface supports script filters, which allow external commands to provide dynamic results in the launcher. This feature uses a subset of the Alfred Script Filter JSON format.

When the configured keyword is typed, the script is executed with the remaining input passed as the final argument. The script must print JSON to stdout. On selection, the item's arg value (or title if arg is absent) is copied to the clipboard using wl-copy. Alternatively, a custom action can be configured to run any command with the selected value substituted via {value} placeholder. A secondary_action can also be defined, which is triggered with Alt+Enter instead of Enter.

The title and subtitle fields support ANSI color codes in JSON output, which the launcher renders as colored text. For example, the pr.py script from alfred-pr-workflow uses colors to display pull request states.

See below for how to configure this

Web Searches

The native interface supports quick web searches via URL templates. Type a configured keyword followed by your query, and the launcher will open your default browser with the search results.

Example: typing g rust traits opens Google search for "rust traits" in your browser.

Common search engines are pre-configured in the example config (Google, DuckDuckGo, GitHub, Wikipedia, etc.), and you can add any search engine by providing a URL template with a {query} placeholder.

See below for how to configure this

File Browser

The native interface includes a built-in file browser. Typing / browses the root filesystem and ~ browses the home directory. Selecting a directory navigates into it, while selecting a file opens it with xdg-open. Alt+Enter copies the file path to the clipboard instead. Tab autocompletes the selected entry into the search bar. Ctrl+H toggles hidden file visibility. Text after the last / fuzzy-filters the current directory listing (e.g., /home/us filters /home/ by "us"). Directories are listed first in accent colour.

The file browser is enabled by default and can be disabled or configured under addons.file_browser (see below).

Configuration

Fuzzel Configuration

Fuzzel appearance can be configured through ~/.config/fuzzel/fuzzel.ini. Refer to the Fuzzel manual for full details.

Example:

dpi-aware=yes
font=RobotoMonoNerdFont-Thin:size=16
terminal=kitty
width=50
layer=overlay
exit-on-keyboard-focus-loss=no
inner-pad=15
fields=filename,name

[colors]
background=282a36ff
text=f8f8f2ff
match=8be9fdff
selection-match=8be9fdff
selection=44475add
selection-text=f8f8f2ff
border=bd93f9ff

Raffi Configuration

Configuration is stored in:

$HOME/.config/raffi/raffi.yaml

Basic example:

firefox:
  binary: firefox
  args: [--marionette]
  icon: firefox
  description: Firefox browser with marionette enabled

The binary field defines the executable. If the binary is not present in PATH, the entry is ignored. The description field defines the label shown in the launcher. The args field defines optional command‑line arguments. The icon field defines an icon name or absolute path. Icons are cached and can be refreshed with -r. The script field defines inline script content. The disabled field hides the entry when set to true.

General Settings

Persistent defaults can be set under a general key. These are equivalent to command‑line flags and are overridden by them.

general:
  ui_type: native
  theme: light
  no_icons: true
  default_script_shell: /bin/zsh
  theme_colors:
    accent: "#cba6f7"

The ui_type field selects the interface (fuzzel or native). The theme field selects the colour theme for the native interface. dark (default) uses a Dracula‑inspired palette; light uses Rose Pine Dawn. The no_icons field disables icon loading when set to true. The default_script_shell field sets the default interpreter for inline scripts.

Individual theme colours can be customised under theme_colors. Each field accepts a hex colour string (#RGB, #RRGGBB, or #RRGGBBAA). Only the colours you specify are overridden; the rest come from the base theme.

Available colour keys: bg_base, bg_input, accent, accent_hover, text_main, text_muted, selection_bg, border.

Example (Catppuccin Mocha on top of the dark base theme):

general:
  theme: dark
  theme_colors:
    bg_base: "#1e1e2e"
    bg_input: "#313244"
    accent: "#cba6f7"
    accent_hover: "#89b4fa"
    text_main: "#cdd6f4"
    text_muted: "#6c7086"
    selection_bg: "#45475a"
    border: "#585b70"

Scripts

Entries can run inline scripts instead of binaries. Scripts use bash by default, or another interpreter if configured via --default-script-shell or by explicitly setting binary.

Example:

hello_script:
  script: |
    echo "hello world and show me your env"
    env
  description: "Hello Script"
  icon: "script"

Python example:

hello_script:
  binary: python3
  script: |
    import os
    print("hello world and show me your env")
    print(os.environ)
  description: "Hello Python script"
  icon: "script"

Conditional Display

Entries can be shown or hidden based on simple conditions. Only one condition is supported per entry.

Conditions include checking whether a binary exists, whether an environment variable is set, not set, or equal to a specific value.

Example:

ifenveq: [DESKTOP_SESSION, GNOME]
ifenvset: WAYLAND_DISPLAY
ifexist: firefox

Path Expansion

Config values for most fields except the script field support path expansion:

  • ~/ is expanded to the user's home directory
  • ${VAR} is replaced with the environment variable value (unset variables expand to empty string)

Example:

myapp:
  binary: ${HOME}/bin/myapp
  args: ["${XDG_DATA_HOME}/files", "~/Documents"]
  icon: ~/icons/myapp.png
  ifexist: ~/bin/myapp

Addon Configuration

The native interface includes optional addons for calculations, currency conversion, file browsing, script filters, and web searches.

addons:
  currency:
    enabled: true
    trigger: ""
    default_currency: EUR
    currencies: ["EUR", "USD", "GBP"]
  calculator:
    enabled: true
  file_browser:
    enabled: true
    show_hidden: false

The enabled field controls whether the addon is active. The show_hidden field for the file browser sets the initial hidden-file visibility (default false; toggled at runtime with Ctrl+H). The trigger field sets the character that activates currency conversion. Defaults to $ if omitted. Can be set to , £, or any other symbol. The default_currency field sets the source currency used when none is specified (e.g., €10 to GBP converts from EUR). Defaults to USD if omitted. The currencies field for the currency addon defines which currencies are available for conversion. You don't need to add a prefix for the calculator; simply typing a valid expression will show the result.

All three addons are enabled by default.

Script Filters Configuration

Script filters are configured under addons.script_filters. Here is an example using the batz time converter (shown in the screenshot above):

addons:
  script_filters:
    - name: "Timezones"
      keyword: "tz"
      command: "batz"
      args: ["-j"]
      icon: "clock"

This will parse the output of batz -j and display it in the launcher when the user types tz followed by a query. The script must output JSON in the format described below.

An example with both a primary and secondary action:

addons:
  script_filters:
    - name: "Bookmarks"
      keyword: "bm"
      command: "my-bookmark-script"
      args: ["-j"]
      action: "echo -n {value}|wl-copy"
      secondary_action: "xdg-open {value}"

Here, pressing Enter copies the selected bookmark URL to the clipboard, while Alt+Enter opens it in the default browser.

Here is the meaning of each field in the script filter configuration:

Field Required Description
name yes Display name shown during loading
keyword yes Text that activates the script filter
command yes Executable to run
args no Arguments passed before the query
icon no Fallback icon name for results without their own
action no Command template run on Enter; {value} is replaced with the selected value. Executed via sh -c. If omitted, the value is copied to the clipboard with wl-copy.
secondary_action no Command template run on Alt+Enter; same {value} substitution and sh -c execution as action. If omitted, Alt+Enter behaves the same as Enter.

The script must output JSON matching this structure (a subset of Alfred's format):

{
  "items": [
    {
      "title": "New York",
      "subtitle": "EST (UTC-5) — 14:30",
      "arg": "America/New_York",
      "icon": { "path": "/usr/share/icons/clock.png" }
    }
  ]
}
Field Required Description
title yes Main text displayed for the item
subtitle no Secondary text shown below the title
arg no Value copied to clipboard (falls back to title)
icon.path no Absolute path to a PNG or SVG icon

Web Search Configuration

Web searches are configured under addons.web_searches. Each entry defines a keyword and URL template:

addons:
  web_searches:
    - name: "Google"
      keyword: "g"
      url: "https://google.com/search?q={query}"
      icon: "google"

When you type the keyword followed by a space and query (e.g., g rust async), the launcher displays a search row. Pressing Enter opens your browser with the URL template, replacing {query} with your search terms (properly percent-encoded).

Field descriptions:

Field Required Description
name yes Display name shown in the search row (e.g., "Search Google for...")
keyword yes Text that activates the web search (e.g., "g", "ddg")
url yes URL template with {query} placeholder for the search terms
icon no Icon name from your icon cache to display next to the search row

The URL template's {query} placeholder is replaced with your search terms, automatically percent-encoded for safe URL use. For example, g hello world becomes https://google.com/search?q=hello%20world.

Development

Contributions are welcome. Issues, feature requests, and pull requests can be submitted via GitHub.

To enable pre‑commit hooks that run cargo clippy before pushing:

pip install pre-commit
pre-commit install

Screenshots

File Browser (/)

optimized-file-browse

Currency Converter ($)

image

Calculator

image

Script Filter with github PR browser

optimized-pull-requests-dashboard

Script Filter with timezone converter

image

Light Theme

suspend-to-sleep-then-hibernate

Licence

This project is released under the MIT Licence.

Author

Chmouel Boudjnah

About

fuzzel/iced launcher based on yaml configuration

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Contributors 6

Languages