vikingowl 3349350bf6 fix: robustness — RwLock for concurrent reads, log malformed JSON requests
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.
2026-03-26 16:39:10 +01:00

Owlry

AUR Rust License GTK4 Wayland

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 (requires owlry-lua or owlry-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

Description
No description provided
Readme GPL-3.0 738 KiB
Languages
Rust 89.4%
CSS 8.5%
Just 2%
Shell 0.1%