Replace Mutex with RwLock for ProviderManager and FrecencyStore in the IPC server. Most request types (Query, Providers, Submenu, PluginAction) only need read access and can now proceed concurrently. Only Launch (frecency write) and Refresh (provider write) acquire exclusive locks. Also adds a warn!() log for malformed JSON requests before sending the error response, improving observability for debugging client issues. Provider trait now requires Send + Sync to satisfy RwLock's Sync bound on the inner type. RuntimeProvider and LuaProvider gain the corresponding unsafe impl Sync.
Owlry
A lightweight, owl-themed application launcher for Wayland, built with GTK4 and Layer Shell.
Features
- Client/daemon architecture — Instant window appearance, providers stay loaded in memory
- Modular plugin architecture — Install only what you need
- Fuzzy search with tags — Fast matching across names, descriptions, and category tags
- 13 native plugins — Calculator, clipboard, emoji, weather, media, and more
- Widget providers — Weather, media controls, and pomodoro timer at the top of results
- Config profiles — Named mode presets for different workflows
- Filter prefixes — Scope searches with
:app,:cmd,:tag:development, etc. - Frecency ranking — Frequently/recently used items rank higher
- Toggle behavior — Bind one key to open/close the launcher
- GTK4 theming — System theme by default, with 9 built-in themes
- Wayland native — Uses Layer Shell for proper overlay behavior
- Extensible — Create custom plugins in Lua or Rune
Installation
Arch Linux (AUR)
# Minimal core (applications + commands only)
yay -S owlry
# Add individual plugins
yay -S owlry-plugin-calculator owlry-plugin-weather
# Or install bundles:
yay -S owlry-meta-essentials # calculator, system, ssh, scripts, bookmarks
yay -S owlry-meta-widgets # weather, media, pomodoro
yay -S owlry-meta-tools # clipboard, emoji, websearch, filesearch, systemd
yay -S owlry-meta-full # everything
# For custom Lua/Rune plugins
yay -S owlry-lua # Lua 5.4 runtime
yay -S owlry-rune # Rune runtime
Available Packages
| Package | Description |
|---|---|
owlry |
Core: UI client (owlry) and daemon (owlry-core) |
owlry-plugin-calculator |
Math expressions (= 5+3) |
owlry-plugin-system |
Shutdown, reboot, suspend, lock |
owlry-plugin-ssh |
SSH hosts from ~/.ssh/config |
owlry-plugin-clipboard |
History via cliphist |
owlry-plugin-emoji |
400+ searchable emoji |
owlry-plugin-scripts |
User scripts |
owlry-plugin-bookmarks |
Firefox, Chrome, Brave, Edge bookmarks |
owlry-plugin-websearch |
Web search (? query) |
owlry-plugin-filesearch |
File search (/ filename) |
owlry-plugin-systemd |
User services with actions |
owlry-plugin-weather |
Weather widget |
owlry-plugin-media |
MPRIS media controls |
owlry-plugin-pomodoro |
Pomodoro timer widget |
Build from Source
Dependencies:
# Arch Linux
sudo pacman -S gtk4 gtk4-layer-shell
# Ubuntu/Debian
sudo apt install libgtk-4-dev libgtk4-layer-shell-dev
# Fedora
sudo dnf install gtk4-devel gtk4-layer-shell-devel
Build (requires Rust 1.90+):
git clone https://somegit.dev/Owlibou/owlry.git
cd owlry
# Build core only (daemon + UI)
cargo build --release -p owlry -p owlry-core
# Build specific plugin
cargo build --release -p owlry-plugin-calculator
# Build everything
cargo build --release --workspace
Install locally:
just install-local
This installs both binaries, all plugins, runtimes, and the systemd service files.
Getting Started
Owlry uses a client/daemon architecture. The daemon (owlry-core) loads providers and plugins into memory. The UI client (owlry) connects to the daemon over a Unix socket for instant results.
Starting the Daemon
Choose one of three methods:
1. Compositor autostart (recommended for most users)
Add to your compositor config:
# Hyprland (~/.config/hypr/hyprland.conf)
exec-once = owlry-core
# Sway (~/.config/sway/config)
exec owlry-core
2. Systemd user service
systemctl --user enable --now owlry-core.service
3. Socket activation (auto-start on first use)
systemctl --user enable owlry-core.socket
The daemon starts automatically when the UI client first connects. No manual startup needed.
Launching the UI
Bind owlry to a key in your compositor:
# Hyprland
bind = SUPER, Space, exec, owlry
# Sway
bindsym $mod+space exec owlry
Running owlry a second time while it is already open sends a toggle command — the window closes. This means a single keybind acts as open/close.
If the daemon is not running when the UI launches, it will attempt to start it via systemd automatically.
Usage
owlry # Launch with all providers
owlry -m app # Applications only
owlry -m cmd # PATH commands only
owlry -m calc # Calculator plugin only (if installed)
owlry --profile dev # Use a named profile from config
owlry --help # Show all options with examples
Profiles
Profiles are named sets of modes defined in your config:
[profiles.dev]
modes = ["app", "cmd", "ssh"]
[profiles.media]
modes = ["media", "emoji"]
[profiles.minimal]
modes = ["app"]
Launch with a profile:
owlry --profile dev
You can bind different profiles to different keys:
# Hyprland
bind = SUPER, Space, exec, owlry
bind = SUPER, D, exec, owlry --profile dev
bind = SUPER, M, exec, owlry --profile media
dmenu Mode
Owlry is dmenu-compatible. Pipe input for interactive selection — the selected item is printed to stdout (not executed), so you pipe the output to execute it.
dmenu mode is self-contained: it does not use the daemon and works without owlry-core running.
# Screenshot menu (execute selected command)
printf '%s\n' \
"grimblast --notify copy screen" \
"grimblast --notify copy area" \
"grimblast --notify edit screen" \
| owlry -m dmenu -p "Screenshot" \
| sh
# Git branch checkout
git branch | owlry -m dmenu -p "checkout" | xargs git checkout
# Kill a process
ps -eo comm | sort -u | owlry -m dmenu -p "kill" | xargs pkill
# Select and open a project
find ~/projects -maxdepth 1 -type d | owlry -m dmenu | xargs code
# Package manager search
pacman -Ssq | owlry -m dmenu -p "install" | xargs sudo pacman -S
# Open selected file
ls ~/Documents | owlry -m dmenu | xargs xdg-open
The -p / --prompt flag sets a custom label for the search input.
Keyboard Shortcuts
| Key | Action |
|---|---|
Enter |
Launch selected item |
Escape |
Close launcher / exit submenu |
Up / Down |
Navigate results |
Tab |
Cycle filter tabs |
Shift+Tab |
Cycle filter tabs (reverse) |
Ctrl+1..9 |
Toggle tab by position |
Search Prefixes
| Prefix | Provider | Example |
|---|---|---|
:app |
Applications | :app firefox |
:cmd |
PATH commands | :cmd git |
:sys |
System actions | :sys shutdown |
:ssh |
SSH hosts | :ssh server |
:clip |
Clipboard | :clip password |
:bm |
Bookmarks | :bm github |
:emoji |
Emoji | :emoji heart |
:script |
Scripts | :script backup |
:file |
Files | :file config |
:calc |
Calculator | :calc sqrt(16) |
:web |
Web search | :web rust docs |
:uuctl |
systemd | :uuctl docker |
:tag:X |
Filter by tag | :tag:development |
Trigger Prefixes
| Trigger | Provider | Example |
|---|---|---|
= |
Calculator | = 5+3 |
calc |
Calculator | calc sqrt(16) |
? |
Web search | ? rust programming |
web |
Web search | web linux tips |
/ |
File search | / .bashrc |
find |
File search | find config |
Configuration
Owlry follows the XDG Base Directory Specification:
| Path | Purpose |
|---|---|
~/.config/owlry/config.toml |
Main configuration |
~/.config/owlry/themes/*.css |
Custom themes |
~/.config/owlry/style.css |
CSS overrides |
~/.config/owlry/plugins/ |
User plugins (Lua/Rune) |
~/.local/share/owlry/scripts/ |
User scripts |
~/.local/share/owlry/frecency.json |
Usage history |
System locations:
| Path | Purpose |
|---|---|
/usr/lib/owlry/plugins/*.so |
Installed native plugins |
/usr/lib/owlry/runtimes/*.so |
Lua/Rune script runtimes |
/usr/share/doc/owlry/config.example.toml |
Example configuration |
Quick Start
# Copy example config
mkdir -p ~/.config/owlry
cp /usr/share/doc/owlry/config.example.toml ~/.config/owlry/config.toml
Example Configuration
[general]
show_icons = true
max_results = 10
tabs = ["app", "cmd", "uuctl"]
# terminal_command = "kitty" # Auto-detected
# use_uwsm = false # Enable for systemd session integration
[appearance]
width = 850
height = 650
font_size = 14
border_radius = 12
# theme = "owl" # Or: catppuccin-mocha, nord, dracula, etc.
[plugins]
disabled = [] # Plugin IDs to disable, e.g., ["emoji", "pomodoro"]
[providers]
applications = true # .desktop files
commands = true # PATH executables
frecency = true # Boost frequently used items
frecency_weight = 0.3 # 0.0-1.0
# Web search engine: google, duckduckgo, bing, startpage, brave, ecosia
search_engine = "duckduckgo"
# Profiles: named sets of modes
[profiles.dev]
modes = ["app", "cmd", "ssh"]
[profiles.media]
modes = ["media", "emoji"]
See /usr/share/doc/owlry/config.example.toml for all options with documentation.
Plugin System
Owlry uses a modular plugin architecture. Plugins are loaded by the daemon (owlry-core) from:
/usr/lib/owlry/plugins/*.so— System plugins (AUR packages)~/.config/owlry/plugins/— User plugins (requiresowlry-luaorowlry-rune)
Disabling Plugins
Add plugin IDs to the disabled list in your config:
[plugins]
disabled = ["emoji", "pomodoro"]
Plugin Management CLI
# List installed plugins
owlry plugin list
owlry plugin list --enabled # Only enabled
owlry plugin list --available # Show registry plugins
# Search registry
owlry plugin search "weather"
# Install/remove
owlry plugin install <name> # From registry
owlry plugin install ./my-plugin # From local path
owlry plugin remove <name>
# Enable/disable
owlry plugin enable <name>
owlry plugin disable <name>
# Plugin info
owlry plugin info <name>
owlry plugin commands <name> # List plugin CLI commands
# Create new plugin
owlry plugin create my-plugin # Lua (default)
owlry plugin create my-plugin -r rune # Rune
# Run plugin command
owlry plugin run <plugin-id> <command> [args...]
Creating Custom Plugins
See docs/PLUGIN_DEVELOPMENT.md for:
- Native plugin development (Rust)
- Lua plugin development
- Rune plugin development
- Available APIs
Theming
Built-in Themes
| Theme | Description |
|---|---|
owl |
Dark theme with amber accents |
catppuccin-mocha |
Soothing pastel |
nord |
Arctic blue palette |
rose-pine |
Natural pine vibes |
dracula |
Dark vampire theme |
gruvbox-dark |
Retro groove |
tokyo-night |
Tokyo city lights |
solarized-dark |
Precision colors |
one-dark |
Atom's One Dark |
[appearance]
theme = "catppuccin-mocha"
Custom Theme
Create ~/.config/owlry/themes/mytheme.css:
:root {
--owlry-bg: #1e1e2e;
--owlry-bg-secondary: #313244;
--owlry-border: #45475a;
--owlry-text: #cdd6f4;
--owlry-text-secondary: #a6adc8;
--owlry-accent: #f38ba8;
--owlry-accent-bright: #f5c2e7;
}
CSS Variables
| Variable | Description |
|---|---|
--owlry-bg |
Main background |
--owlry-bg-secondary |
Secondary surfaces |
--owlry-border |
Border color |
--owlry-text |
Primary text |
--owlry-text-secondary |
Muted text |
--owlry-accent |
Accent color |
--owlry-accent-bright |
Bright accent |
Architecture
Owlry uses a client/daemon split:
owlry-core (daemon) owlry (GTK4 UI client)
├── Loads config + plugins ├── Connects to daemon via Unix socket
├── Applications provider ├── Renders results in GTK4 window
├── Commands provider ├── Handles keyboard input
├── Plugin loader ├── Toggle: second launch closes window
│ ├── /usr/lib/owlry/plugins/*.so └── dmenu mode (self-contained, no daemon)
│ ├── /usr/lib/owlry/runtimes/
│ └── ~/.config/owlry/plugins/
├── Frecency tracking
└── IPC server (Unix socket)
│
└── $XDG_RUNTIME_DIR/owlry/owlry.sock
The daemon keeps providers and plugins loaded in memory, so the UI appears instantly when launched. The UI client is a thin GTK4 layer that sends queries and receives results over the socket.
For detailed architecture information, see CLAUDE.md.
License
GNU General Public License v3.0 — see LICENSE.
Acknowledgments
- GTK4 — UI toolkit
- gtk4-layer-shell — Wayland Layer Shell
- abi_stable — ABI-stable Rust plugins
- fuzzy-matcher — Fuzzy search