The bookmarks provider opened Firefox's places.sqlite directly via
rusqlite, which pulled libsqlite3-sys with its bundled feature to
compile sqlite3.c statically. In clean Arch chroots the bundled feature
kept slipping out of the resolved feature graph and the chroot build
failed at link time with every sqlite3_* symbol undefined. Inline
features = ["bundled"] on the optional dep didn't help; neither did
the explicit "rusqlite/bundled" feature wiring (commit 7569b2d).
Rather than fight Cargo's resolver further, defer the bookmarks
provider alongside the widgets per the same pattern (D20 -> D22).
Returns in a later 2.x release with a pure-Rust reader:
- Chromium's Bookmarks file is already JSON.
- Firefox exposes JSON backups under ~/.mozilla/firefox/<profile>/
bookmarkbackups/<dated>.jsonlz4 — needs lz4 + JSON parse, no SQLite.
Removed:
- crates/owlry/src/providers/bookmarks.rs
- bookmarks module + registration in providers/mod.rs
- bookmarks feature + rusqlite dep in Cargo.toml
- ProvidersConfig.bookmarks field (existing user configs that still
have 'bookmarks = true' silently ignore it — serde default behavior)
- :bm prefix from README's search-prefix table
- bookmarks acknowledgement in README + ROADMAP roadmap section
Cargo.lock loses rusqlite, libsqlite3-sys, fallible-iterator,
fallible-streaming-iterator, foldhash, hashlink, rsqlite-vfs,
sqlite-wasm-rs (-80 lines).
PKGBUILD: owlry-plugin-bookmarks stays in replaces= (any user who has
it installed still needs a clean upgrade), but moved from the 'folded'
comment block to the 'deferred (D20+)' block.
Docs:
- README: bookmarks removed from optional-providers list, feature
table, search-prefix table, config example. Added to upcoming
roadmap section alongside widgets.
- ROADMAP: 'Bookmarks return' subsection added next to 'Widget
providers return'.
- CLAUDE.md: provider tree updated.
- docs/RESTRUCTURE-V2.md: new decision D22 with chroot-build
rationale; task #6 plugin count 8 -> 7 -> 6.
245 tests pass with --features full (was 252; the 7 bookmarks unit
tests went with the module). Build verified locally; chroot build
should now succeed since libsqlite3-sys is no longer in the graph
at all.
28 KiB
Owlry v2 Restructure Plan
Status: in progress on branch v2 (cut from main @ 1caa050)
Target version: owlry 2.0.0
Scope: repository collapse, C-ABI removal, runtime consolidation, CLI cleanup, single AUR package
Originating issue: #5 uuctl launcher not working — closed by deletion of the C-ABI loader that caused it
0. Decisions log
All design decisions agreed before work started. These are load-bearing — do not silently change them.
| # | Decision | Rationale |
|---|---|---|
| D1 | Collapse to 1 AUR package: owlry |
14 PKGBUILDs maintained in lockstep was the root cost of every API bump. Native plugin distribution was theoretical (no third-party shipped any). |
| D2 | Drop the C-ABI plugin system entirely | Issue #5's root cause: strict api_version != API_VERSION rejection. Compiling providers in eliminates the failure mode. |
| D3 | Drop Rune runtime | Only one user plugin (hyprshutdown) uses Rune; will be ported to Lua. 118 MB dylib for one plugin is not earned. |
| D4 | Use Lua for config + plugins via mlua (Lua 5.4, bundled) — Phase 3+ |
Single language for both configuration and user extension. LuaJIT perf is irrelevant for a config language. |
| D5 | Configs-as-plugins model | owlry.provider {} in init.lua registers a runtime provider treated identically to a built-in. No separate ~/.config/owlry/plugins/ dir. |
| D6 | Daemon as subcommand with -d short alias: owlry daemon or owlry -d |
Single binary; owlryd no longer exists. systemd unit invokes owlry -d. |
| D7 | -m auto as explicit alias for the implicit no-flag default |
Today's accept_all behavior — all enabled providers active, tabs cycle. Pinned with an integration test so refactors can't regress it. |
| D8 | Hard cut on TOML config in a later phase | Migrator command owlry migrate-config reads existing TOML + script plugins, emits init.lua. One-shot; TOML reader deleted in the same release that ships Lua. |
| D9 | AUR ships --features full |
Defaults in Cargo.toml are minimal; AUR PKGBUILD enables everything. End-user picks at runtime via config, not at install time. |
| D10 | Runtime activation is config-driven | Compiled-in ≠ enabled. Config (TOML now, Lua later) decides which providers run. |
| D11 | Drop config_editor provider (1127 LOC) |
An in-launcher settings editor is replaced by editing init.lua + owlry config validate. |
| D12 | Drop scripts provider |
Replaced by owlry.provider {} in Lua config (Phase 3+). |
| D13 | Rename sys → power |
"sys" collides mentally with "systemd". :sys kept as alias. |
| D14 | Keep submenu protocol | Used by systemd provider for service actions. Becomes a method on the Provider trait. |
| D15 | Rename systemd unit owlryd.{service,socket} → owlry.{service,socket} |
Consistent with single-binary collapse. PKGBUILD ships new names; old units cleaned up via replaces=() upgrade path. |
| D16 | Submenu protocol redesign deferred to Phase 5 | Today's SUBMENU:type:data string encoding works. Typed IPC variant is hygiene, not blocking. |
| D17 | Keep the daemon | Cold-start cost (XDG scan, frecency load, provider warm-up) is the real reason the daemon exists. Single-process collapse remains an option to revisit post-2.0 if profiling proves it's free. |
| D18 | TOML reader: hard cut at 3.0.0 | One migration moment. 2.x stays TOML-only; 3.0 ships Lua-only with owlry migrate-config shipping in 2.x as preview. |
| D19 | Lua sandbox (Phase 3): filesystem read + process spawn allowed; no network by default | Launcher needs to read configs and spawn commands. Network access (HTTP, sockets) requires explicit config opt-in. |
| D20 | Widget providers (weather, media, pomodoro) on hold |
UI positioning unresolved. Excluded from Phase 1 conversion entirely — not pulled in, not compiled in. Revisit as a dedicated workstream after 2.0 ships. |
| D21 | Hot-reload of init.lua on save (Phase 3) |
notify crate already a dep. Watch ~/.config/owlry/init.lua and any required files; re-run config eval on change. |
| D22 | Bookmarks provider deferred too | The rusqlite dep (for Firefox places.sqlite) caused libsqlite3-sys/bundled to fall out of the resolved feature graph in clean Arch chroots — every chroot build linked against system sqlite or failed with sqlite3_* undefined-symbol errors. Rather than fight Cargo's resolver, defer the bookmarks provider alongside the widgets. Returns when we wire a pure-Rust path (Firefox JSON backups under bookmarkbackups/; Chromium's Bookmarks is already JSON). |
1. Target shape (post-Phase 2 — what 2.0.0 ships as)
Repo layout
owlry/
├── Cargo.toml -- workspace with single member
├── crates/owlry/
│ ├── Cargo.toml -- one binary, features per provider
│ └── src/
│ ├── main.rs -- subcommand router
│ ├── cli.rs -- clap defs
│ ├── server.rs -- daemon mode (was owlry-core/src/server.rs)
│ ├── client.rs -- IPC client to daemon (UI mode)
│ ├── backend.rs -- abstracts daemon vs local
│ ├── ipc.rs -- Request/Response types
│ ├── filter.rs -- ProviderFilter
│ ├── paths.rs -- XDG paths
│ ├── notify.rs -- desktop notifications
│ ├── theme.rs -- CSS loading
│ ├── config/ -- config loader (TOML in Phase 1, Lua in Phase 3)
│ ├── data/ -- FrecencyStore
│ ├── providers/ -- ALL providers, each gated by feature
│ │ ├── mod.rs -- ProviderManager, Provider traits, ProviderType
│ │ ├── application.rs (feature: app)
│ │ ├── command.rs (feature: cmd)
│ │ ├── calculator.rs (feature: calc)
│ │ ├── converter/ (feature: conv)
│ │ ├── power.rs (feature: power, was sys)
│ │ ├── dmenu.rs (feature: dmenu, moved from owlry/src/providers/)
│ │ ├── bookmarks.rs (feature: bookmarks)
│ │ ├── clipboard.rs (feature: clipboard)
│ │ ├── emoji.rs (feature: emoji)
│ │ ├── ssh.rs (feature: ssh)
│ │ ├── systemd.rs (feature: systemd, type_id "uuctl")
│ │ ├── websearch.rs (feature: websearch)
│ │ └── filesearch.rs (feature: filesearch)
│ │ -- weather, media, pomodoro: deferred (D20)
│ └── ui/ -- GTK4 client
├── data/
│ ├── config.example.toml -- shipped defaults (Phase 1)
│ └── default-config.lua -- shipped defaults (Phase 3+)
├── systemd/
│ ├── owlryd.service -- renamed to owlry.service in Phase 2; ExecStart=/usr/bin/owlry -d
│ └── owlryd.socket -- renamed to owlry.socket
└── aur/owlry/PKGBUILD -- the only AUR package
Deleted entirely
| Path | Reason |
|---|---|
crates/owlry-core/ |
Folded into crates/owlry/ |
crates/owlry-plugin-api/ |
C-ABI gone |
crates/owlry-lua/ |
mlua compiled in via Phase 3 |
crates/owlry-rune/ |
Rune dropped (D3) |
crates/owlry-core/src/plugins/ (entire dir) |
C-ABI loader, runtime loader, manifest, registry, watcher, error |
crates/owlry-core/src/providers/native_provider.rs |
C-ABI bridge |
crates/owlry-core/src/providers/lua_provider.rs |
Old Lua bridge |
crates/owlry-core/src/providers/config_editor.rs |
D11 |
crates/owlry/src/plugin_commands.rs (1296 LOC) |
No plugin CLI |
aur/owlry-core/, aur/owlry-lua/, aur/owlry-rune/ |
Folded into aur/owlry/ |
aur/owlry-plugin-* (none yet in this repo) |
n/a |
aur/owlry-meta-* (essentials, widgets, tools, full) |
Redundant |
owlry-plugins/ sibling repo |
Archived on somegit.dev |
2. CLI shape (post-Phase 1)
owlry launch UI, auto mode (default)
owlry -m auto launch UI, auto mode (explicit alias)
owlry -m <mode> launch UI in single-provider mode
owlry --profile <name> launch UI with a named profile
owlry daemon run daemon (alias: owlry -d)
owlry dmenu [-p <prompt>] dmenu mode (was: owlry -m dmenu)
owlry doctor diagnostics: providers, config, socket, runtime
owlry providers [<name>] list providers (or show one)
owlry config validate check config for errors
owlry config show print resolved effective config
owlry migrate-config TOML → init.lua (Phase 3+)
Removed CLI surface
The entire owlry plugin ... subcommand tree (~1296 LOC in plugin_commands.rs) is deleted:
list, search, info, install, remove, update, enable, disable, create, validate, runtimes, run, commands.
There is no plugin installation to manage — features are compiled in.
3. Feature names + descriptions
Final naming for cargo features and corresponding provider IDs:
| Feature | CLI mode / prefix | What it does |
|---|---|---|
app |
:app |
XDG desktop applications |
cmd |
:cmd |
Executables on $PATH |
calc |
:calc / = |
Calculator (math expressions, e.g. = 2+2) |
conv |
:conv |
Unit & currency converter (e.g. 5 ft to m) |
power |
:power (:sys alias) |
Shutdown, reboot, logout, suspend, lock — was sys |
dmenu |
(subcommand) | Pipe-based selection — stdin in, selection out |
bookmarks |
:bm |
Browser bookmarks (Firefox, Chromium) |
clipboard |
:clip |
Clipboard history via cliphist/wl-clipboard |
emoji |
:emoji |
Emoji picker (writes via wl-clipboard) |
ssh |
:ssh |
SSH hosts from ~/.ssh/config |
systemd |
:systemd (:uuctl alias) |
systemd user units (type_id stays "uuctl" for config compat) |
websearch |
:web / ? |
Web search (DDG, Google, custom engines) |
filesearch |
:file / / |
File search via fd or mlocate |
weather |
— | Deferred (D20) — not in 2.0.0 |
media |
— | Deferred (D20) — not in 2.0.0 |
pomodoro |
— | Deferred (D20) — not in 2.0.0 |
Cargo feature groups
[features]
default = ["app", "cmd", "calc", "conv", "power", "dmenu"]
full = [
"app", "cmd", "calc", "conv", "power", "dmenu",
"bookmarks", "clipboard", "emoji", "ssh", "systemd",
"websearch", "filesearch",
# widgets (weather, media, pomodoro): deferred (D20)
]
dev-logging = []
AUR PKGBUILD builds with --features full.
4. Runtime config (Phase 1: TOML, Phase 3+: Lua)
Three orthogonal axes:
- Compiled in — Cargo features at build time. AUR ships
full. - Enabled — Config decides which providers actually run.
- Selected —
-m/--profile/ Tab key narrows the active set at use time.
Phase 1 (TOML, kept temporarily)
[general]
tabs = ["app", "cmd", "calc", "conv", "power"] # what shows in auto mode
[providers]
applications = true
commands = true
calculator = true
converter = true
power = true # was `system`
bookmarks = false # opt-in
clipboard = false
# ...etc
Phase 3+ (Lua, target)
local owlry = require("owlry")
owlry.set {
theme = "apex-neon",
width = 850, height = 650,
tabs = { "app", "cmd", "power" },
}
owlry.providers { "app", "cmd", "calc", "conv", "power", "bookmarks", "systemd" }
owlry.provider {
id = "hs", prefix = ":hs", tab_label = "Shutdown",
items = function(_q)
return {
{ name = "Lock", command = "hyprlock" },
{ name = "Shutdown", command = "systemctl poweroff" },
{ name = "Reboot", command = "systemctl reboot" },
}
end,
}
5. Phased plan
Phase 1 — Repo collapse (current)
Goal: single workspace member, single binary, TOML config still works, C-ABI gone, all built-in providers compiled in behind features.
Subtasks (tracked in TaskList):
- ✅ Inventory: map Provider trait + plugin shapes
- Workspace skeleton: collapse to single crate — move
owlry-core/src/*intoowlry/src/, absorb deps, remove other crates from workspace - Delete C-ABI plugin system —
plugins/dir,native_provider.rs,lua_provider.rs,owlry-plugin-apicrate; stripProviderManager::new_with_config()of plugin loading - Delete Rune + Lua runtime crates —
crates/owlry-rune/,crates/owlry-lua/ - Delete config_editor + scripts providers
- Convert 6 plugins to native Provider impls — clipboard, emoji, ssh, systemd, websearch, filesearch. Pull source from
owlry-plugins/crates/owlry-plugin-*, convertextern "C"vtable →impl Provider/impl DynamicProvider. Per-plugin mechanical work. Widgets (weather, media, pomodoro) excluded per D20; scripts excluded per D12; bookmarks excluded per D22. - Wire cargo features per provider —
#[cfg(feature = "...")]gating;default/fullfeature groups - Rename
sys→power— file, type_id (in CLI mode mapping table),:syskept as alias, config keyproviders.system→providers.power(with TOML migration shim that reads the old name) - CLI restructure — new clap shape (subcommands
daemon,dmenu,doctor,providers,config,migrate-config); drop entirepluginsubcommand tree; daemon mode viaowlry -d/owlry daemon - Auto-mode integration test —
tests/auto_mode.rsasserts the no-flag default still surfaces results from all enabled providers and tabs matchgeneral.tabs - Phase 1 final build + smoke —
cargo check --workspace,cargo build --release,cargo test, runtime socket smoke
Phase 2 — AUR republish as 2.0.0
Goal: ship the collapsed binary to users. Issue #5 closes by virtue of the C-ABI being gone.
Steps:
- Update
aur/owlry/PKGBUILD:pkgver=2.0.0replaces=('owlry-core' 'owlry-lua' 'owlry-rune' 'owlry-plugin-bookmarks' 'owlry-plugin-clipboard' 'owlry-plugin-emoji' 'owlry-plugin-filesearch' 'owlry-plugin-media' 'owlry-plugin-pomodoro' 'owlry-plugin-scripts' 'owlry-plugin-ssh' 'owlry-plugin-systemd' 'owlry-plugin-weather' 'owlry-plugin-websearch' 'owlry-meta-essentials' 'owlry-meta-widgets' 'owlry-meta-tools' 'owlry-meta-full')conflicts=(<same list>)provides=(<same list>)build()usescargo build --release --features fullpackage()installs single binary, single systemd service+socket, default config
- Delete the 14 other PKGBUILDs under
aur/ git tag owlry-v2.0.0- Push, build,
aur-publish - Archive
owlry-pluginssibling repo on somegit.dev (read-only, history preserved) - Comment on issue #5: "fixed by 2.0 rewrite; the C-ABI plugin loader that produced this class of bug has been removed"
Phase 3 — Lua config core (later release: 2.1.0 or 3.0.0)
Goal: replace TOML with Lua-driven config. Hyprland-style configs-as-code.
Steps:
- Add
mlua = { version = "0.11", features = ["lua54", "vendored", "send", "serialize"] }dependency - Build the
owlry.*Lua API surface:owlry.set { ... }— global settings (theme, dimensions, tabs)owlry.providers { ... }— enable list (subset of compiled-in features)owlry.provider { id, prefix, tab_label, items, ... }— register a runtime providerowlry.bind(key, action)— keybinding overridesowlry.theme(name | { ... })— theme selection or inline definition
- Resolve config:
~/.config/owlry/init.luaif present; else fall back to shippeddata/default-config.lua owlry migrate-configsubcommand: read existingconfig.toml(+~/.config/owlry/plugins/*if any) and emit equivalentinit.lua- Wire
owlry config validateandowlry config showto surface Lua errors and resolved state - Decision pending: hard cut TOML in 3.0.0 vs. dual-read in 2.1.0 → cut in 3.0.0
Phase 4 — Configs-as-plugins (same release as Phase 3)
Goal: Lua-registered providers are first-class. Drop the script plugin discovery dir.
Steps:
owlry.provider {}creates aLuaProviderthat wraps the supplied Lua closures and implements theProvidertrait- Remove the
~/.config/owlry/plugins/filesystem discovery entirely - The shipped
default-config.luashowcases at least one inline provider as documentation
Phase 5 — Hygiene
Goal: clean up debt that the collapse uncovered.
Steps:
- Update
CLAUDE.md— binary name (owlry, notowlry-core/owlryd), workspace layout, drop "Phase 5 pending" wording - Update
README.md— new CLI, new install instructions, drop AUR package list - Refresh
ROADMAP.md - Split files >1000 LOC:
providers/mod.rs— separateProviderType/LaunchItem/ItemSourcefromProviderManagerui/main_window.rs— input handling, render, signal wiring as separate modulesproviders/converter/units.rs— move data tables to aunits.tomlresource
- Fix double-daemon spawn: rely on socket activation only; add
flockguard inmain.rsif needed - Make sure systemd unit name is
owlry.service(orowlryd.service?) — decide before AUR ship
6. Provider-by-provider conversion notes (Phase 1.6)
Mechanical pattern for each plugin: drop extern "C" exports, PluginItem → LaunchItem, opaque ProviderHandle → struct field on a Provider impl.
provider_kind-driven categorization (current state)
| Plugin | Kind | Submenu? | Per-keystroke? | Notes |
|---|---|---|---|---|
| DEFER | — | — | D22 — rusqlite/bundled fragile in chroot; returns with a pure-Rust reader | |
| clipboard | Static | yes (?) | no | Uses cliphist, wl-clipboard |
| emoji | Static | no | no | Bundled emoji data; writes via wl-clipboard |
| ssh | Static | no | no | Parses ~/.ssh/config |
| systemd | Static | yes | no | type_id "uuctl"; SUBMENU: protocol for service actions |
| scripts | DELETE | — | — | Replaced by Lua config (D12) |
| websearch | Dynamic | no | yes | per-keystroke; ? trigger |
| filesearch | Dynamic | no | yes | per-keystroke; / trigger; fd or mlocate |
| DEFER | — | — | D20 — UI positioning unresolved | |
| DEFER | — | — | D20 — UI positioning unresolved | |
| DEFER | — | — | D20 — UI positioning unresolved |
Submenu mechanism on Provider trait
Add to pub trait Provider:
/// Returns submenu actions for the given encoded data string, or empty if none.
/// Called when a user selects an item whose command field starts with "SUBMENU:".
fn submenu_actions(&self, _data: &str) -> Vec<LaunchItem> { Vec::new() }
/// Handle a plugin-defined action command (e.g. "POMODORO:start").
/// Returns true if handled.
fn execute_action(&self, _command: &str) -> bool { false }
/// Optional UI hints — replace today's hardcoded match table.
fn prefix(&self) -> Option<&str> { None }
fn icon(&self) -> Option<&str> { None }
fn position(&self) -> ProviderPosition { ProviderPosition::Normal }
fn priority(&self) -> u32 { 0 }
ProviderManager::query_submenu_actions and execute_plugin_action route to these trait methods instead of the C-ABI NativeProvider.
7. Breaking changes / migration impact
What users lose at 2.0.0
- 14 separate AUR packages → 1 (paru handles via
replaces/conflicts) - Ability to install a subset of plugins via AUR (still possible via
cargo install --no-default-features --features ...) - Rune scripting (the user's
hyprshutdownplugin breaks; will be ported to Lua in Phase 3, or compiled into a small custom build) - Dynamic plugin loading at runtime (was never used by anyone outside Owlibou)
~/.config/owlry/plugins/directory (Phase 4 — but already orphaned at 2.0.0 since Rune is gone)
What stays unchanged for users
- Launcher behavior, keybindings, themes, search prefixes
- Mode flags:
-m app,-m systemd,-m uuctl(alias),-m power(was-m sys) - TOML config compatibility through 2.x — until Phase 3 hard-cut to Lua
- Socket protocol (mostly —
Request::PluginListis dropped;SubmenuandPluginActionstay) - systemd integration (unit file invokes
owlry -dinstead ofowlryd)
replaces=() array for aur/owlry/PKGBUILD (2.0.0)
owlry-core
owlry-lua
owlry-rune
owlry-plugin-bookmarks
owlry-plugin-clipboard
owlry-plugin-emoji
owlry-plugin-filesearch
owlry-plugin-media
owlry-plugin-pomodoro
owlry-plugin-scripts
owlry-plugin-ssh
owlry-plugin-systemd
owlry-plugin-weather
owlry-plugin-websearch
owlry-meta-essentials
owlry-meta-widgets
owlry-meta-tools
owlry-meta-full
8. Open questions — RESOLVED
All section-8 questions from the original plan have been answered. Captured as D15–D21 in section 0.
| Original question | Resolution | Recorded as |
|---|---|---|
| systemd unit name | Rename to owlry.{service,socket} |
D15 |
| Submenu protocol redesign | Deferred to Phase 5 | D16 |
| Drop daemon entirely? | No — cold-start cost justifies it | D17 |
| TOML reader removal timing | Hard cut at 3.0.0 | D18 |
| Lua sandbox model | fs read + process spawn allowed; no network by default | D19 |
| Widget positioning | On hold; widgets excluded from Phase 1 | D20 |
| Hot-reload init.lua | Yes (Phase 3) | D21 |
Newly open (post-resolution)
| Question | Defer to | Notes |
|---|---|---|
| Widget rework: keep the "Widget position" UI concept, redesign, or drop entirely? | Post-2.0 workstream | Pulled out of Phase 1 scope per D20. Decide before re-introducing weather/media/pomodoro. |
owlry migrate-config shipped in 2.x as preview, or only at 3.0.0? |
Phase 3 planning | Lean toward shipping in 2.1.0 as a preview so users can test their migrations before TOML is gone. |
9. Build / verify checklist (Phase 1 acceptance)
Phase 1 is "done" when all of these pass:
cargo check --workspace(no warnings on default features)cargo check --workspace --all-features(no warnings)cargo build --release --features fullcargo test --workspace --all-featurescargo clippy --workspace --all-features -- -D warningscargo fmt --all --check- Workspace contains only
crates/owlrymember crates/owlry-core/,crates/owlry-plugin-api/,crates/owlry-lua/,crates/owlry-rune/no longer exist- No occurrences of
owlry_plugin_api,mlua,libloading,Rune,liblua.so,librune.sooutside historical docs target/release/owlryruns:owlry --helpshows new subcommand structureowlry doctorreports providers + config + socket statusowlry -dstarts daemon; socket listens at$XDG_RUNTIME_DIR/owlry/owlry.sockowlry -m systemdshows systemd units (Issue #5 fixed locally)owlry(no flags) shows auto mode with results from all enabled providers, tabs matchgeneral.tabs
- Integration test
tests/auto_mode.rspasses - No daemon double-spawn (verify
pgrep -af owlryshows one process when launched normally)
10. Working notes (mutable)
This section captures in-progress state. Update freely as work proceeds.
- Branch:
v2, cut frommain @ 1caa050on 2026-05-13 - Checkpoints landed:
163e68a— plan doc2fc976b— D15–D21 resolutionsae4a903— C-ABI demolition: tasks #3/#4/#5 done in one commit1d20754— TDD characterization pass (+36 tests)0a4a090— Workspace collapse: owlry-core merged into owlry (task #2)eb8a65f— systemd provider converted (issue #5 functional fix in v2)cb2ea59— Remaining 6 plugins converted in parallel: bookmarks, clipboard, emoji, filesearch, ssh, websearch (tasks #6 + #7)d1c3270+1ba0a97— sys → power rename (task #8)27e2683— CLI subcommand restructure + doctor/providers/config/migrate-config (task #9)e9f310d— auto-mode integration test (task #10)c48efaa— cargo fmt pass0376abd— OWLRY_SOCKET env override (smoke-test enabler)
Phase 1 status: COMPLETE — 11/11 tasks done. Ready for Phase 2 (AUR republish as 2.0.0).
Phase 1 acceptance results:
- ✅
cargo check --workspace(no default features) — clean - ✅
cargo check --workspace --features full— clean - ✅
cargo build --release --features full— 1m 19s - ✅
cargo test --workspace --features full— 252 tests pass (225 unit + 5 auto-mode + 14 ipc + 8 server) - ✅
cargo clippy --workspace --features full— only 10 style warnings (sort_by_keysuggestions, all benign) - ✅
cargo fmt --all --check— clean afterc48efaa - ✅ Workspace contains only
crates/owlrymember - ✅
crates/owlry-core/,crates/owlry-plugin-api/,crates/owlry-lua/,crates/owlry-rune/removed - ✅ No occurrences of
owlry_plugin_api,mlua,libloading,liblua.so,librune.so - ✅
target/release/owlry --helpshows new subcommand structure - ✅
owlry -dstarts daemon, socket binds at$XDG_RUNTIME_DIR/owlry/owlry.sock - ✅
owlry doctorreports config + socket + 8 provider IDs - ✅
owlry providerslists all registered providers;owlry providers uuctlshows the systemd provider details (id, prefix, icon, etc.) - ✅ Issue #5 functionally fixed: systemd provider compiled in AND verified live —
owlry providers uuctl dbusreturns dbus-broker + at-spi-dbus-bus from the running daemon's realsystemctl --user list-unitsinvocation. 43 user units loaded at refresh time. - ✅ Every provider entry point smoke-tested with proper
modesparameter: 13/13 produced expected output (app→Firefox, cmd→git*, power→Shutdown, bookmarks→GitHub*, clipboard→50 entries, emoji→heart*, ssh→aur.archlinux.org, uuctl→dbus-broker, calc 2+2→4, conv 5 ft to m→1.524 m, websearch→Search URL, filesearch→file matches). - ⚠️ Daemon double-spawn: pre-existing PIDs 3042 + 3278 still around (not Phase 1 work; addressed in Phase 5 hygiene)
Known follow-ups (deferred, not blocking 2.0.0 ship):
- Dynamic providers (calc, conv, filesearch, websearch) don't appear in
available_providers()— pre-existing behavior matched the old impl. Worth surfacing indoctorlater. - 10 clippy
sort_by_keystyle warnings — Phase 5 cleanup. refresh_widgets()no-op stub inbackend.rs— remove when widgets are revisited (D20 work).- Tasks done: #1 inventory, #3 delete C-ABI, #4 delete Rune+Lua crates, #5 delete config_editor (scripts never lived in this repo)
- Tasks remaining (Phase 1): #2 workspace collapse, #6 convert 8 plugins, #7 cargo features, #8 sys→power rename, #9 CLI subcommands, #10 auto-mode test, #11 final build+smoke
- Stray processes from inventory phase:
- PIDs 3042, 3278 — pre-existing
owlryd(double-spawn bug; will resolve via Phase 5) - PID 594897 — test daemon from inventory probe; harness denied kill; resolves at next reboot or user kill
- PIDs 3042, 3278 — pre-existing
- Hyprland exec-once for owlryd: suspected source of double-spawn; verify and remove during Phase 5
plugin-api-v1.0.1git tag: still hasAPI_VERSION = 3. Moot now — C-ABI deleted.- Known clippy nits (Phase 5 cleanup): ~8
sort_by→sort_by_keysuggestions inproviders/mod.rsand currency provider. Style only, not blocking. refresh_widgets()stub inbackend.rs: retained as a no-op since the UI still calls it. Delete when widgets are revisited (post-2.0 per D20).systemprovider rename topower(D13): pending Task #8. Internal type_id and config key stillsystem. Test names still usesys_plugin.