Files
owlry-plugins/CLAUDE.md

6.7 KiB

CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

Overview

Official native plugins for the Owlry application launcher. Each plugin is compiled as a shared library (.so) and loaded by the owlry-core daemon at runtime via the ABI-stable plugin interface.

Build & Development Commands

just build          # Debug build (all plugins)
just release        # Release build (all plugins, LTO + stripped)
just plugin <name>  # Build specific plugin release (e.g., just plugin calculator)
just plugins        # Alias for release build of all plugins
just check          # cargo check + clippy
just test           # Run tests
just fmt            # Format code
just show-versions  # List all plugin crate versions
just install-local  # Build release + install all .so to /usr/lib/owlry/plugins/

# Build a specific plugin manually
cargo build -p owlry-plugin-calculator --release
# Output: target/release/libowlry_plugin_calculator.so

# Bump versions
just bump-crate owlry-plugin-weather 0.5.0  # Bump specific plugin
just bump-all 0.5.0                          # Bump all plugins

# Tagging convention: every changed crate gets its own tag
# Format: {crate-name}-v{version}
# Examples:
#   owlry-plugin-bookmarks-v1.0.1
#   owlry-plugin-calculator-v1.0.1
#
# IMPORTANT: After bumping, tag EVERY changed plugin crate individually.
# Unchanged plugins don't need new tags.
#
# Plugin API dependency uses a git tag from the core repo:
#   owlry-plugin-api = { git = "...", tag = "plugin-api-v1.0.1" }
# Update this tag reference when the core repo bumps plugin-api.

Workspace Structure

owlry-plugins/
├── Cargo.toml                          # Workspace root
├── crates/
│   ├── owlry-plugin-bookmarks/         # Firefox/Chrome bookmarks
│   ├── owlry-plugin-calculator/        # Math expression evaluation
│   ├── owlry-plugin-clipboard/         # Clipboard history (cliphist)
│   ├── owlry-plugin-emoji/             # Emoji picker
│   ├── owlry-plugin-filesearch/        # File search (fd/mlocate)
│   ├── owlry-plugin-media/             # Media player controls (widget)
│   ├── owlry-plugin-pomodoro/          # Pomodoro timer (widget)
│   ├── owlry-plugin-scripts/           # User script runner
│   ├── owlry-plugin-ssh/               # SSH host picker
│   ├── owlry-plugin-system/            # System actions (shutdown, reboot, etc.)
│   ├── owlry-plugin-systemd/           # systemd user unit control
│   ├── owlry-plugin-weather/           # Weather display (widget)
│   └── owlry-plugin-websearch/         # Web search providers
├── aur/                                # AUR PKGBUILDs for all plugins + meta-packages
└── docs/                               # Plugin development documentation

Plugin API Dependency

All plugins depend on owlry-plugin-api from the core repo. Currently referenced as a local path (for development), will be a git dependency for releases:

# In each plugin's Cargo.toml
[dependencies]
owlry-plugin-api = { path = "/path/to/owlry/crates/owlry-plugin-api" }

Each plugin crate is compiled as cdylib:

[lib]
crate-type = ["cdylib"]

Plugin Architecture

Every plugin exports a single C-ABI function:

#[no_mangle]
pub extern "C" fn owlry_plugin_vtable() -> &'static PluginVTable

The PluginVTable provides function pointers for:

  • info() - Plugin metadata (name, version, description)
  • providers() - List of providers the plugin offers (id, name, prefix, icon, position, priority)
  • provider_init(id) - Initialize a provider instance
  • provider_refresh(handle) - Populate/reload items (static providers)
  • provider_query(handle, query) - Search items (dynamic providers)
  • provider_drop(handle) - Clean up provider instance

All types cross the ABI boundary using abi_stable crate types (RVec, RStr, RString, etc.).

Provider Categories

Category Plugins Behavior
Static bookmarks, clipboard, emoji, scripts, ssh, system, systemd refresh() populates items at startup; query() filters them
Dynamic calculator, websearch, filesearch query() generates results per keystroke
Widget weather, media, pomodoro Displayed at top of results via position: Widget

Submenu System

Plugins can return items with SUBMENU:plugin_id:data as the command. When the user selects such an item, the daemon calls provider_query(handle, "?SUBMENU:data") to get contextual action items (e.g., systemd service start/stop/restart).

Adding a New Plugin

  1. Create crate: cargo init --lib crates/owlry-plugin-myplugin
  2. Set crate-type = ["cdylib"] in Cargo.toml
  3. Add owlry-plugin-api and abi_stable dependencies
  4. Implement owlry_plugin_vtable() returning a static PluginVTable
  5. Add the crate to workspace members in root Cargo.toml
  6. Register the provider ID prefix in the core repo's ProviderFilter if desired

See docs/PLUGIN_DEVELOPMENT.md for detailed guidance.

AUR Packaging

The aur/ directory contains PKGBUILDs for:

Category Packages
Plugins (13) owlry-plugin-{bookmarks,calculator,clipboard,emoji,filesearch,media,pomodoro,scripts,ssh,system,systemd,weather,websearch}
Meta-bundles owlry-meta-essentials, owlry-meta-widgets, owlry-meta-tools, owlry-meta-full

Plugin .so files are installed to /usr/lib/owlry/plugins/ with consistent naming: libowlry_plugin_*.so.

All plugin PKGBUILDs include .install files that clean up old plugin files on upgrade.

Testing

# Run all plugin tests
just test

# Test a specific plugin
cargo test -p owlry-plugin-calculator

Most plugins are tested via their query() and refresh() implementations. The owlry-plugin-api crate provides the types needed for test assertions.

External Dependencies

Some plugins require external tools at runtime:

Plugin Dependencies
clipboard cliphist, wl-clipboard
filesearch fd or mlocate
emoji wl-clipboard, noto-fonts-emoji
systemd systemd (user services)
bookmarks None (bundled SQLite via rusqlite)
media D-Bus (MPRIS)
websearch xdg-open or configured browser

Key Patterns

  • All plugins are cdylib crates producing .so files
  • ABI stability via abi_stable crate - never break the vtable contract
  • Plugin API v3: ProviderInfo includes position (Normal/Widget) and priority fields
  • Plugins have independent versions from the core (currently 0.4.x)
  • No direct dependency on GTK or UI code - plugins are pure data providers