From db9e7c28301b8096ff36ed124d9030dba6684cd5 Mon Sep 17 00:00:00 2001 From: Levi Neely <141506390+lneely@users.noreply.github.com> Date: Mon, 6 Jul 2026 00:09:28 +0200 Subject: [PATCH] phase 8: service scripts and README - systemd user unit (services/ollie-kde.service) - OpenRC user service (services/ollie-kde.openrc) - Comprehensive README with build, install, usage, D-Bus API docs --- Makefile | 83 +++++++++++++- README.md | 219 +++++++++++++++++++++++++++++++++++++ services/ollie-kde.openrc | 12 ++ services/ollie-kde.service | 12 ++ 4 files changed, 323 insertions(+), 3 deletions(-) create mode 100644 README.md create mode 100755 services/ollie-kde.openrc create mode 100644 services/ollie-kde.service diff --git a/Makefile b/Makefile index 01f9f41..1ba8620 100644 --- a/Makefile +++ b/Makefile @@ -54,7 +54,7 @@ plasmoid-install: daemon /usr/lib64/qt6/qml/org/ollie/private/libollie-plasmoid-pluginplugin.so sudo cp $(BUILD_DIR)/org/ollie/private/ollie-plasmoid-plugin.qmltypes \ /usr/lib64/qt6/qml/org/ollie/private/ - sudo cp $(BUILD_DIR)/libollie-plasmoid-plugin.so /usr/lib64/ + sudo cp $(BUILD_DIR)/lib/libollie-plasmoid-plugin.so /usr/lib64/ printf 'module org.ollie.private\nplugin ollie-plasmoid-pluginplugin\ntypeinfo ollie-plasmoid-plugin.qmltypes\ndepends QtQuick\n' | \ sudo tee /usr/lib64/qt6/qml/org/ollie/private/qmldir > /dev/null sudo ldconfig @@ -68,5 +68,82 @@ plasmoid-uninstall: @echo "Plasmoid uninstalled." install: daemon - install -Dm755 $(BUILD_DIR)/ollie-kde $(DESTDIR)/usr/bin/ollie-kde - install -Dm644 $(LIB_DIR)/libollie.so $(DESTDIR)/usr/lib/libollie.so + @echo "=== Installing ollie-kde ===" + # Daemon + shared library + sudo install -m755 $(BUILD_DIR)/ollie-kde /usr/bin/ + sudo install -m755 $(BUILD_DIR)/ollie-tray /usr/bin/ + sudo install -m755 $(LIB_DIR)/libollie.so /usr/lib64/ + # KRunner plugin + sudo install -m755 $(BUILD_DIR)/lib/kf6/krunner/krunner_ollie.so \ + /usr/lib64/qt6/plugins/kf6/krunner/ + # Kate plugin + sudo install -m755 $(BUILD_DIR)/lib/kf6/ktexteditor/ollie_kate.so \ + /usr/lib64/qt6/plugins/kf6/ktexteditor/ + # Plasmoid QML plugin + sudo mkdir -p /usr/lib64/qt6/qml/org/ollie/private + sudo cp $(BUILD_DIR)/org/ollie/private/ollie-plasmoid-pluginplugin.so \ + /usr/lib64/qt6/qml/org/ollie/private/libollie-plasmoid-pluginplugin.so + sudo cp $(BUILD_DIR)/org/ollie/private/ollie-plasmoid-plugin.qmltypes \ + /usr/lib64/qt6/qml/org/ollie/private/ + sudo install -m755 $(BUILD_DIR)/lib/libollie-plasmoid-plugin.so /usr/lib64/ + printf 'module org.ollie.private\nplugin ollie-plasmoid-pluginplugin\ntypeinfo ollie-plasmoid-plugin.qmltypes\ndepends QtQuick\n' | \ + sudo tee /usr/lib64/qt6/qml/org/ollie/private/qmldir > /dev/null + # Plasmoid package + kpackagetool6 -t Plasma/Applet -u plasmoid/ 2>/dev/null || \ + kpackagetool6 -t Plasma/Applet -i plasmoid/ + # Dolphin service menus + helpers + mkdir -p ~/.local/share/kio/servicemenus + install -m755 dolphin/ollie-actions.desktop ~/.local/share/kio/servicemenus/ + sudo install -m755 dolphin/ollie-ask /usr/local/bin/ + sudo install -m755 dolphin/ollie-session-here /usr/local/bin/ + # Service setup (detect init system) + @if [ -d /etc/user/init.d ] || rc-status --version 2>/dev/null | grep -q "0\.\(6[0-9]\|[7-9]\)"; then \ + echo "=== OpenRC detected (user services) ==="; \ + sudo install -m755 services/ollie-kde.openrc /etc/user/init.d/ollie-kde; \ + echo "Run: rc-update --user add ollie-kde default"; \ + echo "Run: rc-service --user ollie-kde start"; \ + elif [ -d /run/systemd/system ]; then \ + echo "=== systemd detected ==="; \ + mkdir -p ~/.config/systemd/user; \ + install -m644 services/ollie-kde.service ~/.config/systemd/user/; \ + echo "Run: systemctl --user enable --now ollie-kde"; \ + else \ + echo "=== WARNING: No supported init system detected ==="; \ + echo "Neither OpenRC (>=0.60) nor systemd found."; \ + echo "You will need to start ollie-kde manually or set up"; \ + echo "autostart for your session manager (e.g. XDG autostart)."; \ + fi + # Finalize + sudo ldconfig + kquitapp6 krunner 2>/dev/null; true + @echo "" + @echo "=== Installation complete ===" + @echo "Restart Kate, KRunner, and plasmashell to pick up plugins." + +uninstall: + @echo "=== Uninstalling ollie-kde ===" + # Stop service + rc-service --user ollie-kde stop 2>/dev/null; true + rc-update --user del ollie-kde 2>/dev/null; true + systemctl --user disable --now ollie-kde 2>/dev/null; true + # Daemon + shared library + sudo rm -f /usr/bin/ollie-kde /usr/bin/ollie-tray + sudo rm -f /usr/lib64/libollie.so /usr/lib64/libollie-plasmoid-plugin.so + # KRunner plugin + sudo rm -f /usr/lib64/qt6/plugins/kf6/krunner/krunner_ollie.so + # Kate plugin + sudo rm -f /usr/lib64/qt6/plugins/kf6/ktexteditor/ollie_kate.so + # Plasmoid QML plugin + sudo rm -rf /usr/lib64/qt6/qml/org/ollie + # Plasmoid package + kpackagetool6 -t Plasma/Applet -r org.ollie.plasmoid 2>/dev/null; true + # Dolphin service menus + helpers + rm -f ~/.local/share/kio/servicemenus/ollie-actions.desktop + sudo rm -f /usr/local/bin/ollie-ask /usr/local/bin/ollie-session-here + # Service files + sudo rm -f /etc/user/init.d/ollie-kde + rm -f ~/.config/systemd/user/ollie-kde.service + # Finalize + sudo ldconfig + kquitapp6 krunner 2>/dev/null; true + @echo "=== Uninstall complete ===" diff --git a/README.md b/README.md new file mode 100644 index 0000000..3614c1f --- /dev/null +++ b/README.md @@ -0,0 +1,219 @@ +# ollie-kde + +KDE-native integration for [ollie](https://github.com/lkn/ollie) — a long-lived +D-Bus daemon that manages AI agent sessions, with thin KDE clients (system tray, +Plasmoid, KRunner, Kate plugin, Dolphin menus). + +## Architecture + +``` +┌──────────────────────────────────────────────────────────────┐ +│ Plasma Desktop │ +│ System Tray │ KRunner │ Plasmoid │ Kate Plugin │ Dolphin │ +└──────────────────────────┬───────────────────────────────────┘ + │ D-Bus (org.ollie.SessionManager) +┌──────────────────────────┴───────────────────────────────────┐ +│ ollie-kde daemon │ +│ C++ Qt6 │ D-Bus adaptor │ libollie.so (Go) │ +└──────────────────────────────────────────────────────────────┘ +``` + +The daemon owns all sessions and the Go runtime (libollie.so). KDE components +are pure D-Bus clients — lightweight, stateless, and independently restartable. + +## Dependencies + +- Go 1.25+ +- Qt 6 (Core, DBus, Widgets, Quick) +- KDE Frameworks 6 (StatusNotifierItem, Runner, TextEditor, CoreAddons, Config) +- Plasma 6 (for Plasmoid) +- ECM (Extra CMake Modules) +- ollie/core (sibling directory at `../ollie/core`) + +## Build + +```sh +make # builds libollie.so (Go) then ollie-kde + ollie-tray (CMake) +``` + +Outputs: +- `build/libollie.so` — Go shared library (cgo c-shared) +- `build-cmake/ollie-kde` — D-Bus daemon +- `build-cmake/ollie-tray` — system tray icon +- `build-cmake/lib/kf6/krunner/krunner_ollie.so` — KRunner plugin +- `build-cmake/lib/kf6/ktexteditor/ollie_kate.so` — Kate plugin +- `build-cmake/org/ollie/private/` — Plasmoid QML plugin + +## Install + +```sh +# Daemon + tray +sudo install -m755 build-cmake/ollie-kde /usr/bin/ +sudo install -m755 build/libollie.so /usr/lib64/ + +# KRunner plugin +sudo cp build-cmake/lib/kf6/krunner/krunner_ollie.so /usr/lib64/qt6/plugins/kf6/krunner/ + +# Kate plugin +sudo cp build-cmake/lib/kf6/ktexteditor/ollie_kate.so /usr/lib64/qt6/plugins/kf6/ktexteditor/ + +# Plasmoid +make plasmoid-install + +# KRunner (restart needed) +make krunner-install + +# Dolphin service menus +make dolphin-install + +# System tray (optional standalone) +sudo install -m755 build-cmake/ollie-tray /usr/bin/ +``` + +## Service Setup + +### systemd (user unit) + +```sh +cp services/ollie-kde.service ~/.config/systemd/user/ +systemctl --user enable --now ollie-kde +``` + +### OpenRC (user service, 0.60+) + +```sh +sudo cp services/ollie-kde.openrc /etc/user/init.d/ollie-kde +rc-update --user add ollie-kde default +rc-service --user ollie-kde start +``` + +### Manual + +```sh +make run # foreground, for development +``` + +## Usage + +### D-Bus API + +The daemon registers as `org.ollie.SessionManager` on the session bus. + +```sh +# Create a session +dbus-send --session --dest=org.ollie.SessionManager --type=method_call --print-reply \ + /org/ollie/SessionManager org.ollie.SessionManager.CreateSession \ + string:"$HOME" string:"" string:"" string:"default" + +# Submit a prompt +dbus-send --session --dest=org.ollie.SessionManager --type=method_call --print-reply \ + /org/ollie/SessionManager org.ollie.SessionManager.Submit \ + string:"" string:"your prompt here" + +# Get chat output +gdbus call --session --dest org.ollie.SessionManager --object-path /org/ollie/SessionManager \ + --method org.ollie.SessionManager.GetChat "" 0 +``` + +### KRunner + +- `ollie ` — one-shot: creates session, submits, shows popup with result +- `ollie list` — show active sessions +- `ollie kill ` — terminate a session + +### Dolphin + +Right-click any file or directory: +- **Ask Ollie about this** — one-shot prompt with file context, shows result in kdialog +- **Start Ollie session here** — creates a persistent session in that directory + +### Kate + +Enable the "Ollie" plugin in Settings → Configure Kate → Plugins. Panel appears +on the right with: +- Session indicator + CWD label +- **New** — create session in project/file directory +- **Ask File** — send current file path for description +- **Explain** — send selected text for explanation +- Prompt input for free-form messages +- Live-streaming chat view + +### Plasmoid + +Add the "Ollie" widget to your panel or desktop: +- Session list with state indicators (○ idle, ● thinking, ⚡ tool call) +- Live chat view with auto-scroll +- Inline prompt input +- Real-time updates via D-Bus signals + +### System Tray + +- Tooltip: session count +- Status: passive (no sessions), active (sessions idle), attention (agent working) +- Right-click: New Session, Sessions submenu (kill each), Stop All, Quit + +## D-Bus Interface + +Methods: +- `CreateSession(cwd, backend, model, agent) → session_id` +- `ListSessions() → [id\tstate\tmodel\tagent, ...]` +- `KillSession(session_id) → success` +- `RenameSession(session_id, new_name) → success` +- `Submit(session_id, prompt) → success` +- `Interrupt(session_id) → success` +- `GetState(session_id) → state` +- `GetChat(session_id, offset) → text, new_offset` +- `GetUsage(session_id) → usage` +- `GetCost(session_id) → cost` +- `GetConfig(session_id) → key=value pairs` +- `SetConfig(session_id, key, value) → success` +- `GetContext(session_id) → JSONL messages` +- `ListBackends() → [names]` +- `ListModels(session_id) → [names]` +- `ListAgents() → [names]` +- `PeerAdd(session_id, peer_id) → success` +- `PeerRemove(session_id, peer_id) → success` +- `PeerList(session_id) → [peer_ids]` +- `PeerSubmit(session_id, peer_id, prompt) → success` + +Signals: +- `SessionCreated(session_id)` +- `SessionKilled(session_id)` +- `StateChanged(session_id, new_state)` +- `ChatUpdated(session_id, offset, new_text)` + +## File Layout + +``` +ollie-kde/ +├── Makefile # Go + CMake orchestration +├── CMakeLists.txt +├── lib/ +│ └── capi.go # cgo exports (libollie.so) +├── daemon/ +│ ├── main.cpp # D-Bus registration, event loop +│ ├── session_manager.h/cpp # D-Bus adaptee, bridges C API +│ └── org.ollie.SessionManager.xml +├── tray/ +│ ├── main.cpp +│ └── ollie_tray.h/cpp # KStatusNotifierItem +├── krunner/ +│ ├── metadata.json +│ └── ollie_runner.h/cpp # KRunner plugin +├── kate/ +│ ├── metadata.json +│ └── ollie_kate.h/cpp # KTextEditor plugin +├── plasmoid/ +│ ├── metadata.json +│ ├── contents/ui/main.qml +│ └── plugin/ +│ └── olliedbusclient.h/cpp # QML singleton (D-Bus client) +├── dolphin/ +│ ├── ollie-actions.desktop # Service menu entries +│ ├── ollie-ask # One-shot helper script +│ └── ollie-session-here # Session creation helper +├── services/ +│ ├── ollie-kde.service # systemd user unit +│ └── ollie-kde.openrc # OpenRC service +└── test-e2e.sh # End-to-end test script +``` diff --git a/services/ollie-kde.openrc b/services/ollie-kde.openrc new file mode 100755 index 0000000..4c5db48 --- /dev/null +++ b/services/ollie-kde.openrc @@ -0,0 +1,12 @@ +#!/usr/bin/openrc-run +# OpenRC user service for ollie-kde daemon +# Install: sudo cp to /etc/user/init.d/ollie-kde +# Enable: rc-update --user add ollie-kde default + +description="Ollie KDE Session Manager" +supervisor="supervise-daemon" +command="/usr/bin/ollie-kde" + +depend() { + need dbus +} diff --git a/services/ollie-kde.service b/services/ollie-kde.service new file mode 100644 index 0000000..206b9bf --- /dev/null +++ b/services/ollie-kde.service @@ -0,0 +1,12 @@ +[Unit] +Description=Ollie KDE Session Manager +After=dbus.service + +[Service] +ExecStart=/usr/bin/ollie-kde +Restart=on-failure +RestartSec=3 +Environment=LD_LIBRARY_PATH=/usr/lib64 + +[Install] +WantedBy=default.target