systemd-client
The definitive Python library for systemd. Manage services, create units, read journals, analyze security, control resources, and monitor everything — from Python or the terminal.
Documentation: kalexnolasco.github.io/systemd-client
Features
| Category | What you can do |
|---|---|
| Unit Management | list, status, cat, start, stop, restart, reload, try-restart, reload-or-restart, enable, disable, mask, unmask, reset-failed, kill |
| Unit File Builder | Create .service, .timer, .socket, .path files with a fluent Python API |
| Install / Uninstall | Deploy unit files, create drop-in overrides, uninstall units |
| Transient Units | Run commands as systemd services without creating files (systemd-run) |
| Journal | Query with filters (unit, priority, time range, grep) + real-time follow |
| Resource Control | Set cgroup limits (CPU, memory, IO), monitor usage, list timers/sockets/dependencies |
| Security Analysis | Boot blame, security scoring (0-10 exposure), unit file verification |
| sd_notify | Notify systemd from your Python service (READY, STATUS, WATCHDOG) |
| Power Management | poweroff, reboot, suspend, hibernate |
| Environment | show/set/unset manager environment variables |
| Sessions | List login sessions and users (loginctl) |
| Interactive TUI | Full dashboard powered by Ratatui (Rust rendering engine) |
| Dual API | Async-first + sync wrappers, identical interfaces |
| Scope | User session (--user) or system-wide (--system) |
| Zero Dependencies | Core library needs nothing beyond Python 3.11+ stdlib |
Install
pip install systemd-client # Core (zero deps)
pip install systemd-client[tui] # + Interactive TUI (ratatui-py)
pip install systemd-client[dbus] # + D-Bus backend (dasbus)
pip install systemd-client[all] # Everything
Quick Start
Manage services
from systemd_client import SystemdClient
with SystemdClient() as client:
# List all running services
for unit in client.list_units(unit_type="service"):
print(f"{unit.name}: {unit.active_state} ({unit.sub_state})")
# Get detailed status
status = client.status("my-app.service")
print(f"PID: {status.main_pid}, Since: {status.active_enter_timestamp}")
# Control services
client.restart("my-app.service")
client.restart_units(["app.service", "worker.service"]) # batch
# Quick checks
print(f"Active: {client.is_active('my-app.service')}")
Create services from Python
from systemd_client import ServiceBuilder, TimerBuilder, SystemdClient
# Build a .service file with a fluent API
unit = (ServiceBuilder("my-app")
.description("My FastAPI Application")
.exec_start("/usr/bin/python3 /opt/app/main.py")
.working_directory("/opt/app")
.user("appuser")
.environment({"PORT": "8080", "ENV": "production"})
.restart("on-failure")
.restart_sec(5)
.wanted_by("default.target")
.build())
# Deploy in one step
with SystemdClient() as client:
client.install(unit)
client.enable("my-app.service")
client.start("my-app.service")
# Create a timer (cron replacement)
timer = (TimerBuilder("backup")
.description("Daily backup")
.on_calendar("*-*-* 02:00:00")
.persistent(True)
.wanted_by("timers.target")
.build())
Run transient units (systemd-run)
with SystemdClient() as client:
# One-off command as a systemd service
result = client.run("/usr/bin/python3 /opt/backup.py", name="backup-task")
print(f"Running: {result.unit_name}")
# Schedule a recurring timer
client.run_on_calendar("daily", "/usr/bin/python3 /opt/cleanup.py")
# With resource limits
client.run("make -j8", properties={"MemoryMax": "2G", "CPUQuota": "50%"})
Monitor resources
with SystemdClient() as client:
# Set cgroup limits
client.set_property("my-app.service", {"MemoryMax": "512M", "CPUQuota": "25%"})
# Check resource usage
usage = client.get_resource_usage("my-app.service")
print(f"CPU: {usage.cpu_usage_nsec / 1e9:.1f}s")
print(f"Memory: {usage.memory_current / 1024**2:.0f}MB")
# List timers
for timer in client.list_timers():
print(f"{timer.name}: {timer.time_left}")
Security analysis
with SystemdClient() as client:
# What's slow at boot?
for entry in client.analyze_blame()[:5]:
print(f"{entry.time_us / 1e6:.3f}s {entry.unit}")
# Security audit (0 = hardened, 10 = exposed)
sec = client.analyze_security("my-app.service")
print(f"Exposure: {sec.exposure}/10.0")
# Verify unit files before deploying
errors = client.analyze_verify("my-app.service")
sd_notify — from your Python service
# In a Type=notify systemd service:
from systemd_client.notify import SystemdNotifier
notifier = SystemdNotifier()
notifier.ready() # Tell systemd we're up
notifier.status("Listening on :8080") # Update status text
notifier.watchdog() # Keep-alive ping
notifier.stopping() # Graceful shutdown
Async API
import asyncio
from systemd_client import AsyncSystemdClient
async def main():
async with AsyncSystemdClient() as client:
# Concurrent health check
services = ["app.service", "worker.service", "scheduler.service"]
results = await asyncio.gather(
*(client.is_active(svc) for svc in services)
)
for svc, active in zip(services, results):
print(f"{svc}: {'UP' if active else 'DOWN'}")
asyncio.run(main())
System scope
from systemd_client import SystemdClient, SystemdScope
# Manage system-wide services (requires root)
with SystemdClient(scope=SystemdScope.SYSTEM) as client:
units = client.list_units(unit_type="service")
CLI
# Unit management
systemd-client list --type service
systemd-client list-unit-files --state enabled
systemd-client status my-app.service
systemd-client cat my-app.service
systemd-client start my-app.service
systemd-client stop my-app.service
systemd-client restart a.service b.service c.service # batch
systemd-client restart --no-block my-app.service
systemd-client try-restart my-app.service
systemd-client reload-or-restart my-app.service
systemd-client enable my-app.service
systemd-client reset-failed my-app.service
systemd-client kill my-app.service --signal SIGHUP
# Create and deploy unit files
systemd-client create-service --name my-app --exec-start /bin/app --restart on-failure --install
systemd-client create-timer --name backup --on-calendar daily --install
systemd-client install my-app.service --from-file ./my-app.service
systemd-client uninstall my-app.service
# Transient units (systemd-run)
systemd-client run /bin/echo hello --name my-task --wait
systemd-client run /opt/backup.py --on-calendar daily
# Resource monitoring
systemd-client resources my-app.service
systemd-client list-timers
systemd-client list-sockets
systemd-client list-dependencies my-app.service
# Analysis
systemd-client analyze-blame
systemd-client analyze-security my-app.service
systemd-client analyze-verify my-app.service
# Environment and sessions
systemd-client show-environment
systemd-client set-environment MY_VAR=hello
systemd-client list-sessions
systemd-client list-users
# Power management
systemd-client poweroff
systemd-client reboot
systemd-client suspend
# System scope
systemd-client --scope system list --type service
systemd-client --scope system restart nginx.service
# Interactive TUI dashboard
systemd-client tui
systemd-client --scope system tui
# Output formats
systemd-client --json list
systemd-client --no-color status my-app.service
Interactive TUI
Launch the full interactive dashboard:
systemd-client tui
Features:
- Real-time unit list with color-coded states (green=active, red=failed)
- Mouse support: click to select, scroll wheel, tab clicks
- Keyboard:
s=start,S=stop,r=restart,e=enable,d=disable,j=journal - Type filters:
F1=All,F2=Services,F3=Timers,F4=Sockets,F5=Failed - Search:
/to filter by name - Journal panel at bottom with auto-refresh
- Scope toggle with
Tab, 3 tabs: Dashboard, Timers, Help - Powered by Ratatui (Rust rendering engine, 30-60 FPS)
Requires: pip install systemd-client[tui]
Architecture
Your Application
|
+-- SystemdClient (sync)
| |
+-- AsyncSystemdClient (async)
|
+-- SubprocessBackend ---- systemctl --user/--system ----> systemd
| (default, zero deps)
+-- DBusBackend ---------- D-Bus session/system bus ----> systemd
| (optional, dasbus)
+-- AsyncJournalReader --- journalctl --output=json -----> journal
+-- Builders ------------- .service/.timer/.socket/.path -> unit files
+-- Analyze -------------- systemd-analyze ----------------> boot/security
+-- Notify --------------- $NOTIFY_SOCKET -----------------> sd_notify
Requirements
- Python >= 3.11
- Linux with systemd
systemctlandjournalctlon PATH
License
systemd-client · Documentation · GitHub · PyPI
Metadata
Release files for systemd-client 0.9.2
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| systemd_client-0.9.2.tar.gz | 113.4 kB | With provenance | Details for systemd_client-0.9.2.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| systemd_client-0.9.2-py3-none-any.whl | Python 3 | none | any | Details for systemd_client-0.9.2-py3-none-any.whl |
Total release size: 169.3 kB
Release files / systemd_client-0.9.2.tar.gz
| Download URL | systemd_client-0.9.2.tar.gz |
|---|---|
| Size | 113.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
7cce76656301da38d57fe81e2725ab2ea3049306612dfa0c2d894ff4e998df37
|
|
BLAKE2b-256 checksum How to use checksums |
51ec52b26dbd593072bff22ea1a26a615fce1061bec4abdcecd8c51d58592f09
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.7
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Apr 7, 2026.
Transparency logRelease files / systemd_client-0.9.2-py3-none-any.whl
| Download URL | systemd_client-0.9.2-py3-none-any.whl |
|---|---|
| Size | 55.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
5545466cb6298f61f178bcc5e4b86eafa95e3e774770ec7cede232a87847fc0d
|
|
BLAKE2b-256 checksum How to use checksums |
595f133e67c3b7178f5722b03cbe9958007011d27e6a1ae99a3c52d1fd4b1a75
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.7
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Apr 7, 2026.
Transparency logSecurity for systemd-client 0.9.2
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for systemd_client-0.9.2.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Apr 7, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.