Metadata-Version: 2.4
Name: tray4hermes
Version: 2.0.18
Summary: KDE/Plasma tray monitor and controller for Hermes Gateway (Nous Research Hermes Agent)
Author: MoDDO
License-Expression: MIT
Project-URL: Homepage, https://github.com/MoDD0/tray4hermes
Project-URL: Repository, https://github.com/MoDD0/tray4hermes.git
Project-URL: Issues, https://github.com/MoDD0/tray4hermes/issues
Project-URL: Changelog, https://github.com/MoDD0/tray4hermes/blob/main/README.md#roadmap-next-up-ideas
Project-URL: Mirror, https://forgejo.he1.co/HERMbuddy/tray4hermes
Keywords: hermes,hermes-agent,tray,kde,plasma,system-tray,qt5,pyqt5
Classifier: Development Status :: 5 - Production/Stable
Classifier: Environment :: X11 Applications
Classifier: Intended Audience :: End Users/Desktop
Classifier: Operating System :: POSIX :: Linux
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Utilities
Requires-Python: >=3.11
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: PyQt5==5.15.11
Provides-Extra: dev
Requires-Dist: pytest==9.0.0; extra == "dev"
Requires-Dist: pytest-qt==4.5.0; extra == "dev"
Requires-Dist: ruff==0.14.0; extra == "dev"
Requires-Dist: bandit==1.8.6; extra == "dev"
Dynamic: license-file

# tray4hermes

<!-- tray4hermes:version -->
[![version: 2.0.18](https://img.shields.io/badge/version-2.0.18-blue.svg)](https://github.com/MoDD0/tray4hermes)
[![CI](https://github.com/MoDD0/tray4hermes/actions/workflows/ci.yml/badge.svg)](https://github.com/MoDD0/tray4hermes/actions/workflows/ci.yml)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
[![Python 3.11+](https://img.shields.io/badge/python-3.11+-blue.svg)](https://www.python.org/downloads/)
[![Code style: ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json)](https://github.com/astral-sh/ruff)

![KDE Plasma tray with tray4hermes icon](https://raw.githubusercontent.com/MoDD0/tray4hermes/main/docs/images/preview.png)

*A real KDE Plasma 5 tray — the tray4hermes icon slots in next to your
other SNI apps. Screenshot from a Manjaro KDE session where this tray
is live.*

<!-- i18n:available-languages:START -->
<!-- DO NOT EDIT — auto-generated by scripts/i18n_build.py from the files in docs/i18n/. -->
<!-- Available languages: en → English, cs → Čeština -->
<!-- i18n:available-languages:END -->

> **Canonical:** English (this file)
>
> **Other languages:** [Čeština](docs/README.cs.md)

A KDE/Plasma system-tray monitor and controller for **Hermes Gateway**, the
messaging service included with
[Hermes Agent](https://github.com/NousResearch/hermes-agent) by Nous Research.

> tray4hermes is **read-only with respect to Hermes Agent**. It controls
> the gateway via `systemctl --user`, persists one small JSON file of its
> own, and reads everything else. It does not store tokens, does not
> configure providers, does not edit `~/.hermes/config.yaml`. All of
> that lives in Hermes Agent itself.

---

## Overview

`hermes-gateway` runs as a `systemd --user` service. tray4hermes adds a KDE
tray interface for monitoring and controlling it. The application:

- **shows the gateway state** directly in the KDE panel (green/orange/red)
- **lets you Start / Stop / Restart** without opening a terminal
- **switches profiles** (`default`, `work`, `off`…) from a menu
- **displays logs** in a viewer with coloured levels, per-level filters,
  search, traceback awareness and a time-window filter
- **speaks English and Czech**, switchable at runtime without a restart
- **reads Hermes runtime state** and uses the standard `systemctl` API.

> ⚠️ **Disclaimer:** tray4hermes is a *passive convenience addon*, not an
> official Hermes Agent component. Hermes Agent runs perfectly well
> without it. Use it if you like it; ignore it if you don't.

---

## Features

- 📊 **Live status icon** in the system tray (🟢 active, 🟠 warming,
  🔵 activating, ⚫ inactive, 🔴 failed, ⚪ unknown)
- ▶️ **Start / Stop / Restart** of `hermes-gateway.service` in a single click
- 🔄 **Profile switcher** submenu, driven by `~/.hermes/profiles/`
- 📋 **Log viewer** — *see below*, it's quite polished
- ⚙️ **Open Hermes config** in your default editor
- 💻 **Launch Hermes CLI** in a new terminal
- 🛠️ **Settings dialog** — UI language plus the defaults the log viewer
  starts with, stored alongside the rest of the tray state
- 🌍 **English and Czech UI** — pick a language in the Settings dialog and
  the tray re-labels itself immediately, no restart; `tray4hermes -L en`
  (or `cs`) overrides the stored choice for a single run, and
  `tray4hermes --language` lists what the installed build ships

### Log viewer

The log viewer reads `~/.hermes/logs/gateway.log` and provides:

- **Coloured log levels**: `DEBUG` gray, `INFO` white, `WARNING` yellow,
  `ERROR` red, `CRITICAL` red + full-row highlight
- **Line-number gutter** like Qt Creator / VS Code
- **Per-level filters** on a toolbar row of their own, so they and the
  controls above them stay visible instead of collapsing into the `»`
  overflow popup — show only what you want
- **TRACEBACK toggle** — a separate category for stack traces; turn
  it off to see only messages, or on to keep both
- **Time-window filter** (All / 5m / 15m / 1h / 6h / 24h) — show only
  logs from the last hour, etc.
- **Reverse order** — flip to `journalctl` style (newest at top); every new
  entry appears first
- **Max lines** spinbox — rolling buffer (0 = unlimited). Steps by 1; type any value manually
- **Search** in a collapsible find bar under the log (`Ctrl+F` opens and
  focuses it, `F3` next, `Shift+F3` prev, `Esc` closes). It deliberately sits
  outside the toolbar, so it stays reachable at any window width
- **Auto-scroll toggle** (default ON; OFF = preserve position on refresh).
  While investigating, the viewer preserves a manually selected scroll
  position even when auto-scroll is ON; it only follows the live edge when
  you are already viewing that edge
- **Word-wrap toggle**
- **Copy / Clear / Refresh** actions
- **Settings dialog** (font size, max lines, per-level visibility, …)
- **Remembers window size/position** between opens
- **Persisted** — all settings are saved to
  `~/.config/tray4hermes/state.json`

---

## Architecture

```
┌──────────────────────────────────────────────────────┐
│  Hermes Agent (Nous Research)                        │
│  • hermes-gateway.service   (systemd --user)         │
│  • Hermes Desktop           (Electron consumer)      │
│  • CLI / TUI / MCP / Plugins                         │
└──────────────────────┬───────────────────────────────┘
                       │ shares
                       ▼
              ~/.hermes/    ←  single source of truth
              ├── config.yaml
              ├── auth.json
              ├── gateway_state.json
              ├── logs/gateway.log
              └── profiles/<name>/
                       ▲
                       │ reads (read-only)
┌──────────────────────┴───────────────────────────────┐
│  tray4hermes  (this package)                         │
│  • systray icon  • Start/Stop/Restart                │
│  • profile switcher  • log viewer                    │
│  • writes only: ~/.config/tray4hermes/state.json     │
└──────────────────────────────────────────────────────┘
```

The package has zero coupling to the Hermes Agent source code. It only
knows about files in `~/.hermes/`, the systemd unit name, and the path
to the `hermes` CLI. The tray can be uninstalled at any time without
affecting the gateway.

## State machine

The tray combines two sources of truth into six discrete states:

| Code | Icon | Meaning |
|------|------|---------|
| `active` | 🟢 | Gateway running, at least one platform connected |
| `warming` | 🟠 | Gateway running, credentials/platforms still initialising |
| `activating` | 🔵 | systemd is starting the service |
| `inactive` | ⚫ | Gateway stopped |
| `failed` | 🔴 | systemd unit failed |
| `unknown` | ⚪ | Cannot determine state (both sources unavailable) |

`gateway_state.json` is the primary source when fresh (< 1 hour old);
`systemctl is-active` is the fallback. The two-source design avoids
the OAuth warm-up race where the systemd unit shows `active` for a few
seconds before the first model call actually succeeds.

## Requirements

- **Linux** (developed primarily on **Manjaro KDE**; should work on
  any distro with KDE Plasma 5, see [Platform support](#platform-support))
- **KDE Plasma 5** (Plasma 6 uses Qt6 — tray4hermes is Qt5; Qt6 port
  is in the Roadmap)
- Python ≥ 3.11
- A running `hermes-gateway.service` under `systemd --user`
- `loginctl enable-linger $USER` for autostart after logout

## Installation

### End-user (system-wide)

```bash
uv pip install --system tray4hermes
# or with pipx:
pipx install tray4hermes
```

Then enable autostart:

```bash
# Find where the .desktop file ended up after pip install
DESKTOP_FILE=$(python3 -c "import tray4hermes, os; \
  print(os.path.join(os.path.dirname(tray4hermes.__file__), 'data', 'tray4hermes.desktop'))")
cp "$DESKTOP_FILE" ~/.config/autostart/tray4hermes.desktop
# Adjust the Exec= line to point at your installed tray4hermes script
# (the wheel ships it at <prefix>/bin/tray4hermes).
```

### Development (editable)

```bash
git clone https://github.com/MoDD0/tray4hermes.git
cd tray4hermes
uv pip install --system -e ".[dev]"
./scripts/dev.sh   # installs deps + runs tests
```

Launch the tray:

```bash
# Either via the installed console script:
tray4hermes

# Or via the watchdog wrapper (auto-restart on crash):
./run.sh

# Or as a module:
python -m tray4hermes
```

---

## Platform support

**Primarily developed and tested on Manjaro KDE** (rolling release,
Plasma 5, `xcb` X11 backend).

**Should work natively on any Linux that has:**

1. **Qt5 with PyQt5** (`python -c "from PyQt5.QtWidgets import QSystemTrayIcon; print('OK')"`
   should succeed). PySide2 is not supported — every module imports PyQt5
   directly.
2. **DBus session bus** (`echo $DBUS_SESSION_BUS_ADDRESS` should be
   set — typically automatic in a desktop session)
3. **A system tray implementation** respecting the freedesktop.org
   SNI spec (KDE Plasma, Xfce, LXQt, Cinnamon, MATE, GNOME with
   extension, Elementary OS with extension…)
4. **systemd --user** (or something compatible — OpenRC / runit
   alternatives have a slightly different `hermes-gateway` API;
   an adapter in `paths.py` would be needed)

### Distro status

Only one row here is actually tested. The rest is reasoning from how
close the distro is to that one — useful, but not a promise.

| Distro / DE | Status | Notes |
|-------------|--------|-------|
| **Manjaro KDE** | ✅ tested | the platform this is developed and tested on |
| Arch Linux + KDE | 🟡 expected to work | practically identical to Manjaro, just package from `extra` not AUR |
| CachyOS KDE | 🟡 expected to work | Arch-based, practically identical |
| **Ubuntu + KDE** | 🟡 expected to work | see below |
| Fedora + KDE | 🟡 expected to work | `dnf install python3-pyqt5` |
| openSUSE + KDE | 🟡 expected to work | `zypper install python3-PyQt5` |

### Ubuntu with Unity / GNOME / others

This is a **tray application**, so the main difference is tray support:

- **Ubuntu + KDE Plasma** (`apt install kubuntu-desktop`) — should work
  out-of-the-box, you may need to install `python3-pyqt5` via `apt`
  or `pip install PyQt5` for yourself.
- **Ubuntu + Unity (22.04+)** — Unity uses its own indicator tray,
  not SNI. We would need to adapt `icons.py` and `app.py` so they
  register via DBus at `com.canonical.Unity.LauncherEntry`. Technically
  possible, but not implemented today. If you run Unity and want this
  — open an issue.
- **Ubuntu + GNOME 41+** — GNOME intentionally **does not support
  tray** without an SNI extension. You have to install an extension
  like [AppIndicator Support](https://extensions.gnome.org/extension/615/appindicator-support/),
  then it should work.
- **Ubuntu + Cinnamon / MATE / XFCE** — all support SNI tray, should
  work out-of-the-box.

### Practical recommendation for Ubuntu users

Short version: **install KDE Plasma** and it will work with the
highest probability. Not the smallest package, but the cleanest path.

```bash
# 1. Install KDE Plasma desktop (meta-package, ~600 MB)
sudo apt install kde-plasma-desktop

# 2. Log out. On the login screen, choose the "Plasma" session, log in.

# 3. In a terminal inside the KDE session:
sudo apt install python3-pyqt5    # system PyQt5
python3 -m pip install --user tray4hermes  # or from GitHub
python3 -m tray4hermes             # start the tray

# 4. For autostart after login:
# The .desktop file ships inside the installed wheel at:
#   /usr/local/lib/python3.*/site-packages/tray4hermes/data/tray4hermes.desktop
# (resolve with `python3 -c "import tray4hermes; import os; \
#   print(os.path.join(os.path.dirname(tray4hermes.__file__), 'data', 'tray4hermes.desktop'))"`)
# Copy it to ~/.config/autostart/ and edit the Exec= path to point at
# your installed tray4hermes.
```

**Why we recommend this:**

1. **Hermes Agent** runs on Ubuntu exactly the same as on Manjaro
   (both are Linux, both have systemd --user, both have Python 3.11+).
   *No* inherent incompatibility with Ubuntu.
2. **KDE Plasma's tray** implements the SNI spec most thoroughly of
   any DE — no workaround, no extension, no "maybe works".
3. **Higher chance of first-try success.** Instead of 75–95% with GNOME
   / Cinnamon + workaround, you get ~99%.

**Alternative for purists:** if you insist on GNOME and really want
this to work there, follow the instructions in the `Ubuntu + GNOME 41+`
section above. But it's not a trivial first experience.

### Future testing

**A dedicated Ubuntu VM**: if the community brings real demand for
Ubuntu support, we'd happily spin up a simple **Ubuntu LTS VM**
(VirtualBox or LXC) with KDE Plasma in CI and run a smoke test —
`tray4hermes` starts → menu icon appears → click Start/Stop → verify
that `systemctl --user` responds. Cost would be ~1–2 days of setup +
scripts. We don't have it right now, because demand is currently
**zero** (Manjaro/KDE covers ~95% of users who have written to us).
If you'd like it, add it to the Roadmap. Open an issue with a `+1`
and a vote, or just show up to a contributing call. 🙂

### Troubleshooting

If the tray **doesn't show** on another distro:

```bash
# 1. Verify Qt5 sees a system tray
python -c "from PyQt5.QtWidgets import QSystemTrayIcon, QApplication; \
           app = QApplication([]); print('available:', QSystemTrayIcon.isSystemTrayAvailable())"

# 2. Check whether DBus is running
echo "DBus session bus: $DBUS_SESSION_BUS_ADDRESS"

# 3. Try explicit XDG, and run in the foreground so errors reach the terminal
export XDG_CURRENT_DESKTOP=KDE
export XDG_SESSION_TYPE=x11
python -m tray4hermes
```

There is no `--debug` flag: the tray writes its failures to stderr, so
running it from a terminal as above is the whole debug story. `tray4hermes
--version` and `tray4hermes --language` are the only other arguments.

If `QSystemTrayIcon.isSystemTrayAvailable()` returns `False`, it's a
**distro/desktop combo problem**, not a tray4hermes bug. You can:
- open an issue with the output of `python -c "import sys; print(sys.platform, …)"`
  plus your Qt version (`PyQt5.QtCore.PYQT_VERSION_STR`)
- ask in the Hermes community (or directly with us in issues, we'll
  help extend `paths.py` for your setup)

We want it to work **everywhere** Hermes Agent has a chance of running.
So distro-specific PRs are very welcome.

---

## Security

This package **does not handle any credentials, tokens, or secrets**.
The only file it writes is `~/.config/tray4hermes/state.json`, which
contains the currently-selected profile name, log-viewer preferences,
and a schema version:

```json
{
  "version": 1,
  "selected_profile": "default",
  "log_settings": {
    "max_lines": 2000,
    "auto_scroll": true,
    "word_wrap": false,
    "font_size": 9,
    "show_levels": ["ERROR", "WARNING", "INFO", "DEBUG", "CRITICAL", "TRACE"],
    "show_tracebacks": true,
    "time_window_minutes": 0,
    "reverse_order": false
  }
}
```

If you find a security issue, please open a **private** issue via
GitHub's "Report a vulnerability" feature (Settings → Security →
Report a vulnerability). Do **not** disclose vulnerabilities in
public issues or commits.

### Threat model

| Vector | Mitigation |
|--------|------------|
| RCE via malicious `gateway_state.json` | Loaded as JSON only; no `eval`/`exec`/shell. Strict shape. |
| Log injection | Log viewer is read-only; uses `QPlainTextEdit` (escapes HTML). |
| Profile path injection | Profile name validated by Hermes Agent itself (`hermes profile use` returns non-zero on missing). |
| Lock file race | `O_CREAT\|O_EXCL` + PID liveness probe + recursive single retry. |
| Filesystem exhaustion on `state.json` write | Atomic `tmp` + `os.replace`; directory created with `parents=True`. |

The tray is sandboxed against the rest of Hermes Agent: even a
zero-day in tray4hermes cannot read `auth.json`, the `.env` file, or
trigger a model call. The worst it can do is crash and be restarted
by the watchdog — at which point it just reads the (still intact)
state and re-renders the tray icon.

## Development

### Run tests

```bash
./scripts/dev.sh                          # install + pytest
./scripts/dev.sh tests/test_state.py -v   # specific file
```

Tests use `QT_QPA_PLATFORM=offscreen` (set in `tests/conftest.py`) so
they run headless, without a display server.

### Continuous integration

[GitHub Actions](.github/workflows/ci.yml) runs on every push to `main`
and on every pull request: lint (`ruff check` + `ruff format --check`)
and the full test suite on Python 3.11, 3.12 and 3.13 — the versions
this package claims to support. A separate job refuses any commit that
lowers the package version.

### Lint & format

```bash
uv run ruff check src tests
uv run ruff format src tests
```

### Security scan

```bash
uv run bandit -c pyproject.toml -r src
```

### Pre-commit hooks (optional but recommended)

```bash
uv pip install --system pre-commit
pre-commit install
pre-commit run --all-files
```

## Project layout

```
tray4hermes/
├── pyproject.toml            # PEP 621, uv-friendly, exact-pinned deps
├── LICENSE                   # MIT
├── README.md                 # generated from docs/i18n/en.md — don't edit
├── CONTRIBUTING.md
├── CLAUDE.md                 # briefing for AI assistants working here
├── .claude/                  # architecture, conventions, session log, specs
├── .gitignore                # incl. secret patterns
├── .pre-commit-config.yaml
├── run.sh                    # watchdog wrapper
├── docs/
│   ├── README.cs.md          # generated from docs/i18n/cs.md — don't edit
│   ├── i18n/
│   │   ├── en.md             # canonical README source (source of truth)
│   │   └── cs.md             # Czech translation of en.md
│   └── images/
│       ├── preview.png       # screenshot for README
│       └── tray4hermes.png   # package logo
├── scripts/
│   ├── dev.sh                # install + test convenience
│   ├── i18n_build.py         # docs/i18n/*.md → README.md + docs/README.cs.md
│   ├── i18n_compile.sh       # .pot extraction + .po → .mo catalogs
│   ├── i18n_lint.py          # heading parity across README translations
│   └── versioning.py         # SemVer bump helper
├── src/
│   └── tray4hermes/
│       ├── __init__.py       # __version__ (single source of truth)
│       ├── __main__.py       # python -m tray4hermes (argparse entry)
│       ├── app.py            # HermesTray — icon, menu, poll timer
│       ├── state.py          # @dataclass + aggregation logic
│       ├── paths.py          # all filesystem paths and tunables
│       ├── icons.py          # QPainter icon factory
│       ├── lock.py           # single-instance lock
│       ├── log_dialog.py     # LogDialog — editor, gutter, toolbars, find bar
│       ├── log_settings.py   # viewer preferences: dataclass, persistence, dialog
│       ├── log_parse.py      # level / timestamp / traceback parsing (no Qt widgets)
│       ├── log_theme.py      # colours, fonts and filter constants shared by both dialogs
│       ├── tray_settings.py  # global settings dialog (language, defaults)
│       ├── i18n.py           # gettext wrapper + runtime language switch
│       ├── py.typed          # PEP 561 marker
│       ├── _locales/         # UI catalogs, shipped inside the wheel
│       │   ├── tray4hermes.pot
│       │   └── cs/LC_MESSAGES/tray4hermes.{po,mo}
│       └── data/
│           └── tray4hermes.desktop  # ships inside the wheel
└── tests/
    ├── conftest.py
    ├── test_app.py           # Qt offscreen — tray menu and actions
    ├── test_cli.py           # `python -m tray4hermes` argument handling
    ├── test_gateway_control.py   # systemctl actions, profile switching
    ├── test_i18n_build.py    # README build script
    ├── test_i18n_parity.py   # build + lint scripts wired into pytest
    ├── test_i18n_runtime.py  # gettext catalogs, msgid language
    ├── test_launchers.py     # editor / terminal resolution and spawning
    ├── test_lock.py          # single-instance lock
    ├── test_log_parse.py     # level / timestamp parsing, both regex engines
    ├── test_log_refresh.py   # what the viewer shows when the log is unreadable
    ├── test_log_settings.py  # viewer settings persistence
    ├── test_log_shortcuts.py # Ctrl+F / F3 / Shift+F3 / Esc, real key path
    ├── test_log_toolbar.py   # toolbar rows stay on screen at realistic widths
    ├── test_readme_freshness.py  # compiled READMEs match their sources
    ├── test_readme_parity.py # image parity between en.md and cs.md
    ├── test_settings_dialog.py   # log-viewer settings dialog
    ├── test_state.py         # state aggregation and persistence
    ├── test_tray_settings.py # global tray settings
    └── test_versioning.py    # SemVer bump helper
```

## License

MIT — see [LICENSE](LICENSE).

---

## Hosting

**Primary host: GitHub** → https://github.com/MoDD0/tray4hermes

- All development, issues, pull requests, releases, and CI happen there.
- This is where contributors fork from and push branches to.
- Releases are tagged here first; everything else cascades from here.

---

## Contributing

Issues, comments, suggestions — all welcome. Whether it's:

- 🐛 **Bug report** — ideally with the relevant part of
  `~/.hermes/logs/gateway.log` and whatever `python -m tray4hermes`
  prints when run from a terminal
- 💡 **Feature request** — short description of what it would be
  for. We don't mind "wild" ideas (different backend, Wayland
  support, custom icons…). Worth a discussion.
- 🎨 **UI tweak** — colours, layout, fonts, tooltips. This is
  the area where contributor taste matters most.
- 📖 **Documentation** — screenshots of the log viewer are missing;
  feel free to add them
- 🌍 **Localization** — the UI runs through `gettext` and ships English
  and Czech. Another language means one `.po` file under
  `src/tray4hermes/_locales/`; the README translations live separately in
  `docs/i18n/`. Both routes are described in
  [CONTRIBUTING.md](CONTRIBUTING.md)
- 🐧 **Distro-specific fixes** — see [Platform support](#platform-support).
  Every distro we test on is a contribution away

### How to send a PR / patch

```bash
git clone https://github.com/MoDD0/tray4hermes.git
cd tray4hermes
./scripts/dev.sh            # installs deps, runs tests
# make your change
./scripts/dev.sh -v         # re-run tests with verbose
uv run ruff check src tests
uv run ruff format src tests
git commit -m "description"
git push
```

Rules (flexible):

1. **Don't break the tests.** The whole suite must stay green —
   `./scripts/dev.sh` runs it.
2. **Don't add new runtime dependencies** without discussion — the
   package has one runtime dependency (`PyQt5`), and we want to keep it
   that way.
3. **No secrets in the diff**
   (`grep -rE "sk-[a-z0-9]{16,}|api_key.*[a-z0-9]{20,}"`).
4. **No writes to `~/.hermes/*`** from inside the tray — that area is
   owned by Hermes Agent.
5. **MIT-compatible contributions.** If you're adding code, stick to
   the MIT license.

If you like this project and have an idea, **just open an issue** —
we'll discuss it. Even "this word doesn't sound right in the
translation" is welcome feedback.

---

## Roadmap (next-up ideas)

A few things on my mind that aren't done yet. If any of these
interests you more than the rest, speak up:

- **Wayland support** — currently `xcb` (X11) only because of the
  KDE Plasma tray API; Plasma 6 + Qt6 would open Wayland. PRs welcome.
- **Custom icons per status** — SVG icons instead of `QPainter` raster
- **Log search across sessions** (FTS5 over the sessions DB)
- **Notifications on ERROR** — toast over D-Bus when the gateway
  writes a traceback (I like it, but it's a matter of taste)
- **Settings export/import** — sharing log-viewer presets between
  profiles
- **Ubuntu LTS CI VM** — see [Platform support → Future testing](#future-testing)
- **Plasma 6 / Qt6 port** — for the day Manjaro ships Plasma 6 by
  default

