Task: Migrate Qt client to a proper systemd unit
Table of Contents
This page documents a task in the Systemd resource management and per-environment isolation story. It captures the goal, current status, acceptance, and any notes or results.
Goal
Every other ORE Studio process is now started/stopped/tracked via
systemctl --user (concrete, non-templated units generated from
systemd_generate.py). The Qt client is the one exception: it still
uses its own _launch=/=_terminate PID-file bookkeeping
(compass_services.py). Give it a real systemd unit – one concrete
unit per colour instance (red/green/blue/uncoloured can all run
simultaneously today under the PID-file scheme; the systemd version
must preserve that), following the same "site-serve" precedent
(compass site start/stop/status) once that lands.
Status
| Field | Value |
|---|---|
| State | ABANDONED |
| Parent story | Systemd resource management and per-environment isolation |
| Now | Nothing. |
| Waiting on | Nothing. |
| Next | Nothing. |
| Last touched | 2026-08-04 |
Acceptance
- `compass client start/stop` drives a real `systemctl –user` unit per colour instance (concrete, not templated – same lesson the fleet's own units already learned about `%i` specifiers), not the current PID-file `_launch`/`_terminate` path.
- Multiple colour instances (red/green/blue/uncoloured) can still run simultaneously, matching current behaviour.
- `compass client stop –colour <x>` stops only that instance's unit.
- No orphaned `ores.qt` processes left behind after stop.
Plan
Before implementing, verified empirically whether a GUI Qt process
can even run under systemctl --user on this environment
(WSLg/XWayland remote X). It cannot – see * Result. Abandoned once
that was confirmed reproducible; no unit-generation code was written.
Notes
Test Scenarios
Manual QA scenarios (scaffolded via compass add test_scenario, run
through the QA Validation Runner panel) that verify this task. Link
new ones here as they're created; the scenario doc itself links back
via its "Verifies task" field.
| Scenario | State | Notes |
|---|---|---|
PRs
| PR | Title |
|---|---|
| #1833 | [agile] Abandon Qt client systemd migration: X display unreachable |
Review
| # | Comment summary | File | Decision | Notes |
|---|---|---|---|---|
| 1 | story.org State=STARTED but Now/Next/Last touched stale (4 review passes flagged this) | story.org | Accepted | No task in this story is actually in flight (the one started task was abandoned) – reverted State to BACKLOG rather than inventing a fake Now/Next. |
| 2 | Comma splice / missing connector in Result prose | task_migrate_client_to_systemd.org | Accepted | Reworded "…or a broken binary, specifically…" to "…or a broken binary; specifically, …". |
Result
Abandoned after empirical testing showed a real, reproducible blocker, not just an architectural-consistency nice-to-have:
- Launched
ores.qtvia a transientsystemd-run --userunit withDISPLAYexplicitly set (--setenv=DISPLAY=neumann:11.0): failed immediately withqt.qpa.xcb: could not connect to display neumann:11.0, process aborted (SIGABRT). - Retried with
XAUTHORITYalso explicitly set to the working~/.Xauthoritycookie file (confirmed viaxauth listto contain a validMIT-MAGIC-COOKIE-1entry for that exact display): same failure, same crash. - The identical binary launches and renders correctly via a plain
subprocess (i.e. exactly what
compass client start's current PID-file_launchdoes, and what this whole session's screenshot work relied on) – so this isn't a broken X server or a broken binary; specifically, thesystemd --usersession boundary on this WSLg/XWayland setup isn't inheriting (or isn't authorized for) the interactive login session's X access the same way a normal child process is.
Every other ORE Studio process is headless, so the fleet's migration
to systemd never had to cross this boundary. Root-causing why
systemd user sessions can't reach the X display here (session
scoping? cgroup/namespace isolation specific to WSLg? something else
entirely?) is a real, separate investigation with no guaranteed
payoff – and even if solved, the client's per-invocation dynamic args
(colour, --open-scenario path, --master-password) are a
structurally worse fit for systemd's generate-once-at-config-time
unit model than the fleet's static, DB-driven service definitions
ever were. The PID-file lifecycle it has today already satisfies the
actual goal (no orphans, clean start/stop) – it was inconsistent
with the rest of the fleet, but not actually broken. Not worth
pursuing further without a concrete reason beyond consistency.