Skip to content

Script Filters

Script filters allow external commands to provide dynamic results in the launcher using a subset of the Alfred Script Filter JSON format.

Script filters execute external commands when a keyword is typed, displaying dynamic results based on the command’s JSON output. This enables integration with APIs, databases, custom scripts, and more.

Script filter timezone converter example

Configure script filters in your raffi.yaml:

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

name string (required)

Display name shown during loading

keyword string (required)

Text that activates the script filter

command string (required)

Executable to run

args array

Arguments passed before the query

icon string

Fallback icon name for results without their own icon

action string (default: copy)

Action on Enter. Options:

  • "copy": Copy to clipboard
  • "insert": Type into focused app via wtype/ydotool
  • Command template with {value} placeholder (executed via sh -c)

secondary_action string

Action on Ctrl+Enter. Accepts same values as action. If omitted, Ctrl+Enter behaves same as Enter.

Script filters must output JSON matching this structure (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" }
},
{
"title": "London",
"subtitle": "GMT (UTC+0) — 19:30",
"arg": "Europe/London"
}
]
}

title string (required)

Main text displayed for the item

subtitle string

Secondary text shown below the title

arg string

Value copied to clipboard (falls back to title if omitted)

icon.path string

Absolute path to a PNG or SVG icon

  1. Type Keyword

    User types the configured keyword (e.g., tz)

  2. Execute Command

    Script is executed with remaining input as final argument:

    Terminal window
    batz -j "New York"
  3. Parse JSON

    Raffi parses the JSON output from stdout

  4. Display Results

    Items are displayed in the launcher

  5. Handle Selection

    On Enter, the item’s arg value (or title) is used with the configured action

By default, selecting an item copies its value to the clipboard:

script_filters:
- name: "Timezones"
keyword: "tz"
command: "batz"
# Default action is "copy"

Define custom actions using command templates:

action: "echo -n {value}|wl-copy"
script_filters:
- name: "Bookmarks"
keyword: "bm"
command: "bookmark-script"
action: "echo -n {value}|wl-copy" # Enter: Copy URL
secondary_action: "xdg-open {value}" # Ctrl+Enter: Open URL

Copies bookmark URL to clipboard

The title and subtitle fields support ANSI color codes for colored text:

{
"items": [
{
"title": "\u001b[32mSuccess\u001b[0m",
"subtitle": "\u001b[90mCompleted at 14:30\u001b[0m"
}
]
}

Using batz time converter:

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

Usage:

tz New York
# Shows current time in New York
# Press Enter to copy timezone info
GitHub PR browser
script_filters:
- name: "Pull Requests"
keyword: "pr"
command: "gh-pr-script"
args: ["-j"]
icon: "github"
action: "xdg-open {value}"

Usage:

pr my-project
# Lists pull requests for my-project
# Press Enter to open PR in browser
script_filters:
- name: "Bookmarks"
keyword: "bm"
command: "bookmark-manager"
args: ["--json"]
icon: "bookmark"
action: "echo -n {value}|wl-copy"
secondary_action: "xdg-open {value}"

Usage:

bm documentation
# Filters bookmarks by "documentation"
# Enter: Copy URL
# Ctrl+Enter: Open in browser
script_filters:
- name: "Passwords"
keyword: "pw"
command: "pass-json"
icon: "lock"
action: "copy"

Usage:

pw github
# Shows password entries matching "github"
# Press Enter to copy password

The scripts/search/search.py script in the repository provides live DuckDuckGo autocomplete suggestions while opening results in any configured search engine.

Install it first:

Terminal window
mkdir -p ~/.config/raffi/scripts/search
cp scripts/search/search.py ~/.config/raffi/scripts/search/search.py
chmod +x ~/.config/raffi/scripts/search/search.py

Then configure one entry per engine:

script_filters:
- name: "Search DuckDuckGo"
keyword: "ddg"
command: "python3"
args: ["~/.config/raffi/scripts/search/search.py", "duckduckgo"]
icon: "web-browser"
action: "xdg-open {value}"
secondary_action: "copy"
- name: "Search Google"
keyword: "sg"
command: "python3"
args: ["~/.config/raffi/scripts/search/search.py", "google"]
icon: "google"
action: "xdg-open {value}"
secondary_action: "copy"

Supported engines: google, duckduckgo, bing, brave.

Usage:

ddg rust async
# First item: raw query "rust async" → opens DuckDuckGo search
# Remaining items: DDG autocomplete suggestions
# Enter: open in browser
# Ctrl+Enter: copy URL to clipboard

Here’s a simple example script in Python:

#!/usr/bin/env python3
import json
import sys
query = sys.argv[1] if len(sys.argv) > 1 else ""
items = [
{
"title": f"Result for: {query}",
"subtitle": "This is a subtitle",
"arg": f"https://example.com/search?q={query}",
"icon": {"path": "/usr/share/icons/search.png"}
}
]
print(json.dumps({"items": items}))

Make it executable and configure:

Terminal window
chmod +x my-filter.py
script_filters:
- name: "My Filter"
keyword: "mf"
command: "./my-filter.py"
action: "xdg-open {value}"
  • Enter: Execute primary action
  • Ctrl+Enter: Execute secondary action (if configured)
  • Esc: Cancel and return to normal mode
  • ↑/↓: Navigate through results