- Model - Qwen3.8-27B:Q8_0
- Engine - llama.cpp
- Harness - OpenCode
- Microsoft learning MCP
- Task - Create dotnet webapi to control systemd services via D-Bus
- Phase 1 - Research on D-Bus and TMDS library. Result - SKILL.md and docs/README.txt with three additional artifacts. The model was asked to create human-readable README and agent-readable SKILL.
- Phase 2 - Create a dotnet webapi backend using SKILL.md generated during the phase 1.
- Works with user space services only
- Two variants for starting and stopping services
- Waiting for completion - until the job is done
- Streaming intermediate statuses via SSE
- Logging is explicitly disabled to keep logic clearly visible
*** No manual code or docs modifications ***
Reference bundle for building .NET tools that control systemd (PID 1)
through its D-Bus API (org.freedesktop.systemd1) using the
Tmds.DBus library.
| # | Document | For |
|---|---|---|
| 1 | 01-dbus-fundamentals.md |
D-Bus from zero: buses, names/paths/interfaces/members, message types, signatures, the standard Properties interface, introspection, security, busctl toolbox |
| 2 | 02-systemd-dbus-api.md |
The systemd API: object model, path encoding, Manager/Unit/Job interfaces, job modes and results, the job-completion pattern, the Subscribe() gotcha, polkit, error names |
| 3 | 03-tmddbus-library.md |
Tmds.DBus: packages, connections, the XML → C# source generator, proxies/signals/variants/owner-watcher, walkthrough of the example project, pitfalls checklist |
example/SystemdServiceController/ — a console CLI that does what
systemctl does, over D-Bus, with typed generated proxies:
list, files, status, start/stop/restart/reload/try-restart
(with job-completion waiting), enable/disable, is-enabled,
reset-failed, jobs, watch (live PropertiesChanged + JobRemoved),
version.
cd example/SystemdServiceController
dotnet build
dotnet run -- helpRead-only commands work unprivileged; mutating commands need root or the
polkit actions org.freedesktop.systemd1.manage-units /
.manage-unit-files (Part 2, §7).
User-space systemd (addendum). All commands accept a global
--userflag, the equivalent ofsystemctl --user:dotnet run -- --user list # units of the per-user instance dotnet run -- --user start myapp # unit file in ~/.config/systemd/user/
--userswitches the bus only — from the system bus (DBusAddress.System, PID 1) to the session bus (DBusAddress.Session, the per-user systemd instance started by systemd-logind at login). The well-known name, object paths, interfaces, and the whole job-completion pattern are identical (Parts 1–2 all apply unchanged). Differences to keep in mind: the instance requires a running session bus (i.e.$XDG_RUNTIME_DIRset — no--userin headless containers or cron unless you set it up); its unit files live in~/.config/systemd/user/; and the session owner can manage their own units without polkit authentication, because the session bus is already restricted to that user.
Systemd.DBus.cs(repo root) — a statically generated Manager proxy (produced bydotnet dbus codegen --protocol-apifrom a trimmed XML: 4 unit verbs +GetUnit+ 4 signals). Incomplete by design; kept as a reference for what the static codegen path looks like. See Part 3, §8.SKILL.md— machine-oriented instructions for a coding agent to scaffold a new project of this kind from scratch.
- Tmds.DBus documentation: https://tmds.github.io/Tmds.DBus/ (main page,
Tmds.DBus.ProtocolAPI reference). - systemd D-Bus man page:
org.freedesktop.systemd1(5)(https://www.freedesktop.org/software/systemd/man/latest/org.freedesktop.systemd1.html) — the authoritative API description, incl. introspection skeletons. - D-Bus specification: https://dbus.freedesktop.org/doc/dbus-specification.html
- Verified live against systemd 259 (
busctl introspect) on Ubuntu.