Pal
A fast, extensible command palette for Linux. Launch apps, switch windows, control audio, manage clipboard, and more - all from a unified interface.
pal run fzf apps # launch applications
pal run rofi pals # pick a palette to run
pal run fzf combine # combined view of multiple palettes
Features
- Builtin palettes - Apps, bookmarks, processes, and more - no external dependencies
- Builtin frontends - fzf, rofi, and stdin work out of the box
- Plugin system - Extend with bash, python, or any language
- Layered config - Defaults + user config + project config + env vars
- Icon support - Show icons in rofi and other frontends
- Combine palettes - Merge multiple palettes into one view
Installation
Requires Rust 1.70+ (rustup)
Quick Start
# Initialize config at ~/.config/pal/config.toml
# Run with default palette and frontend
# Run specific palette with specific frontend
# List items without frontend (useful for debugging)
# Show loaded configuration
Builtin Palettes
| Palette | Description |
|---|---|
apps |
List and launch desktop applications |
bookmarks |
Browser bookmarks (Firefox/Chrome) |
pals |
List and run other palettes |
psg |
List and kill processes |
combine |
Combine multiple palettes into one |
Builtin Frontends
| Frontend | Description |
|---|---|
fzf |
Terminal fuzzy finder |
rofi |
Desktop launcher with icons |
stdin |
Simple numbered list selection |
Configuration
Config is loaded in order (later overrides earlier):
- Built-in defaults
pal.default.toml(in current directory)~/.config/pal/config.toml(user config)pal.toml(in current directory)-c <path>(CLI argument)PAL_*environment variables
Example Config
[]
= "combine"
= "fzf"
[]
[]
= "builtin/palettes/combine"
= "view-grid"
= ["pals", "quickcmds"]
[]
= "utilities-terminal"
= true
= true
= "~/.config/pal/commands.json"
= "cmd"
= "cmd"
[]
= "~/.config/pal/plugins/audio"
= "audio-card"
Data Files (auto_list)
For simple palettes, use a JSON lines file:
Plugin Development
Plugins are directories with a plugin.toml and an executable.
plugin.toml
= "my-palette"
= "Description of my palette"
= "0.1"
= ["run.sh"]
run.sh
#!/usr/bin/env bash
Plugin Config Access
Plugins receive their config via environment variable:
# In your plugin
cfg=
Remote Plugins
Load plugins directly from GitHub repositories:
[]
= "github:zcag/pal/plugins/palettes/ip"
# With specific branch or tag
[]
= "github:zcag/pal/plugins/palettes/ip@v1.0"
# Data files also support github: URLs
[]
= "github:zcag/pal/plugins/palettes/colors"
= "github:zcag/pal/plugins/palettes/colors/data.json"
Plugins are cloned on first use to ~/.local/share/pal/plugins/ using git sparse checkout. Requires git to be installed.
Example Plugins
The plugins/ directory contains ready-to-use plugins. Use them directly via GitHub:
[]
= "github:zcag/pal/plugins/palettes/audio"
| Plugin | Description |
|---|---|
audio |
Switch audio output devices (PipeWire/PulseAudio) |
clipboard |
Clipboard history (cliphist/clipman) |
wifi |
Connect to WiFi networks (nmcli) |
windows |
Focus windows (Hyprland/Sway/X11) |
systemd |
Manage systemd services |
ble |
Connect Bluetooth devices |
hue |
Control Philips Hue scenes |
repos |
Browse GitHub repositories (gh cli) |
chars |
Unicode character picker |
icons |
Freedesktop icon picker |
nerd |
Nerd Font icon picker |
emoji |
Emoji picker |
colors |
Color picker (hex/rgb/hsl) |
calc |
Calculator (qalc/bc) |
ip |
Network info (public/local IP, gateway, DNS) |
docker |
Docker container management |
op |
1Password items |
media |
Media player control (playerctl) |
power |
Power menu (shutdown, reboot, etc.) |
Actions
Actions define what happens when an item is picked with auto_pick:
[]
= true
= true
= "commands.json"
= "cmd" # run as shell command
= "cmd" # field containing the command
Create custom actions as plugins in plugins/actions/:
# plugins/actions/copy/run.sh
Environment Variables
| Variable | Description |
|---|---|
_PAL_CONFIG |
Path to current config file |
_PAL_CONFIG_DIR |
Directory of current config file |
_PAL_FRONTEND |
Current frontend name |
_PAL_PLUGIN_CONFIG |
JSON config for current plugin |
Tips
Combine for a unified launcher
[]
= "builtin/palettes/combine"
= ["apps", "bookmarks", "quickcmds"]
Different frontends for different contexts
# Terminal
# Desktop (bind to hotkey)
Project-specific palettes
Create pal.toml in your project:
[]
= true
= "scripts.json"
= "cmd"
= "cmd"
Roadmap
-
pal updateto update remote plugins - Prompt support (text input, choice, etc.)
- Caching for slow palettes
-
pal doctorfor config validation - REST API frontend
- More builtin palettes (calendar, OTP, etc.)
Disclaimer
This is a rewrite of my personal bash spaghetti that I implemented over the years, covering many palettes and frontends for various stuff. Inspired by Raycast - an awesome macOS Spotlight alternative that's also quite customizable. Many of the custom palettes here are ported from my custom Raycast plugins after I left macOS.
This is also an experiment for myself on Rust and AI-assisted coding. I have minimal Rust knowledge, and this is my first time properly using an AI agent for development. Claude Code was heavily used in this project - it straight up implemented a ton of the palettes based on my descriptions and reference bash scripts from the original pal.
License
MIT