ubuntu-doctor
Read-only diagnostic CLI for Ubuntu systems, with explained findings and stable JSON output.
Problem
When an Ubuntu machine slows down or misbehaves, the first diagnosis is always the same
sequence of manual commands: df -h, free -h, systemctl --failed, ss -tulpn,
scanning /var/log, checking for broken packages. It is repetitive, easy to miss a step,
and the results end up scattered across several outputs with no interpretation.
ubuntu-doctor runs those checks for you and returns a prioritized, explained report:
what is critical, what is a warning, what is healthy — each finding with a suggested next
step. It is read-only by design and never changes the system.
Features
- Disk usage per mount point (snap/pseudo filesystems excluded)
- Memory and swap, judged by available memory
- CPU load average and the heaviest processes (by name, no command lines)
- Failed
systemdunits - Listening TCP/UDP ports, with owning process where visible
- Oversized log files under
/var/log - Broken packages and pending (security) updates
- Colored text, stable JSON (a documented contract), and sanitized Markdown output
- Severity-based exit codes and graceful degradation without privileges
Architecture
See docs/architecture.md. The rule is: collectors don't decide,
rules don't collect, renderers don't calculate, and the domain core never touches the OS.
flowchart LR
CLI[cli.py] --> ORCH[orchestrator]
ORCH --> COL[collectors]
COL --> RULES[rules]
RULES --> FIND[Finding / Report]
FIND --> REND[render: text / json / markdown]
Requirements
- Ubuntu 22.04 LTS or newer (Debian-family)
- Python 3.11+
Installation
Once published, the recommended install is with pipx:
pipx install ubuntu-doctor
From a clone, using uv:
uv sync
uv run ubuntu-doctor --help
Usage
ubuntu-doctor full-check # run every check and aggregate
ubuntu-doctor disk --json # a single area, machine-readable
ubuntu-doctor cpu --top 10 # ten heaviest processes
ubuntu-doctor export-report -o report.md
Example full-check output (hostname anonymized):
CRITICAL Failed unit: virtualbox.service [failed]
LSB: VirtualBox Linux kernel module
→ Inspect each failed unit with: systemctl status <unit> and
journalctl -u <unit> -b. ubuntu-doctor never restarts services for you.
UNKNOWN Broken packages
Could not determine broken packages: dpkg: ... Permission denied
→ Re-run with sufficient privilege to check: sudo dpkg --audit.
OK Disk usage: / [14.6%]
14.6% used (741.7 GB free of 914.8 GB)
OK Memory usage [36.9%]
36.9% used (14.7 GB available of 23.3 GB); swap 0.0% of 19.7 GB
OK CPU load [3.41]
load average 1.96 / 3.41 / 3.66 on 8 core(s)
OK Listening ports [26]
26 listening ports (17 tcp, 9 udp).
Overall: CRITICAL (myhost)
Commands
| Command | Purpose |
|---|---|
full-check |
Run every check and aggregate |
disk, memory, cpu, services, network, logs, packages |
Run a single area |
export-report |
Write a sanitized Markdown report |
version |
Print the version |
Common options: --json, --verbose, --config PATH. cpu also takes --top N;
export-report takes --output/-o PATH and --force.
Exit codes: 0 no problem · 1 at least one CRITICAL · 2 usage/config error ·
3 internal error.
Configuration
Thresholds resolve from three layers, each overriding the previous: defaults → TOML file → environment.
TOML file (via --config PATH, or ~/.config/ubuntu-doctor/config.toml if it exists):
[thresholds]
disk_warn_percent = 80
disk_crit_percent = 90
mem_warn_percent = 85
mem_crit_percent = 95
log_warn_bytes = 104857600 # 100 MB
log_crit_bytes = 1073741824 # 1 GB
Environment variables override the file:
| Variable | Overrides |
|---|---|
UBUNTU_DOCTOR_DISK_WARN / UBUNTU_DOCTOR_DISK_CRIT |
Disk usage % |
UBUNTU_DOCTOR_MEM_WARN / UBUNTU_DOCTOR_MEM_CRIT |
Memory usage % |
UBUNTU_DOCTOR_LOG_WARN / UBUNTU_DOCTOR_LOG_CRIT |
Log size (bytes) |
There are deliberately no --threshold-* flags: the file and environment already cover
per-threshold overrides without cluttering every command.
The JSON contract
--json emits a stable object with a schema_version (currently 1). Consumers can rely
on the shape; any breaking change bumps schema_version and the package's major version.
Testing
uv run pytest # 149 tests, 100% coverage, fully offline
uv run ruff check .
uv run mypy
Every test runs offline and deterministically. Command-based checks are tested against
real output captured once into tests/fixtures/.
Design decisions
Recorded as ADRs in docs/adr/: pure collectors for testability, psutil
over /proc parsing, read-only by design, and threshold/UNKNOWN semantics.
Troubleshooting
- "Could not determine broken packages: ... Permission denied" —
dpkg --auditneeds the dpkg lock, which requires privilege. This is expected: the check degrades toUNKNOWNrather than failing. Runsudo dpkg --audityourself to check. - Listening ports show no process —
sscannot name processes owned by other users without privilege. The port is still listed; only the owner is hidden. command not foundfor a check — on a minimal systemsystemctl,ssoraptmay be absent; that check reportsUNKNOWNand the rest still run.
Limitations
- Ubuntu/Debian only.
- Read-only: it diagnoses, it never fixes.
- No history and no continuous monitoring in v1 (each run is a snapshot).
- File-permission auditing is deliberately omitted (too prone to false positives).
- Behavior inside containers can differ (cgroup-reported limits).
Roadmap
- v1.1: Docker container check; snap packaging.
- v1.2: optional history in SQLite with run-to-run comparison.
- v2.0: extract the collection layer into a reusable
linuxfactslibrary.
Contributing
Issues and PRs welcome. Please keep the tool read-only, keep tests offline, and run
ruff, mypy and pytest before opening a PR. See the issue and PR templates.
License
MIT — see LICENSE.
Contact
David Oliveira · davidoliveira.devbr@gmail.com
Metadata
Release files for ubuntu-doctor 1.0.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| ubuntu_doctor-1.0.0.tar.gz | 100.1 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| ubuntu_doctor-1.0.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 132.3 kB
Release files / ubuntu_doctor-1.0.0.tar.gz
| Download URL | ubuntu_doctor-1.0.0.tar.gz |
|---|---|
| Size | 100.1 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
cddca0f8931f4657372e903785780caf0b0f55716a0f589124c6d6d1787958b1
|
|
BLAKE2b-256 checksum How to use checksums |
f6fc62dfc130751304d5ae2548a1eed509ad3919054517b4baf6e6067b412519
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.14
|
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 Jul 28, 2026.
Transparency logRelease files / ubuntu_doctor-1.0.0-py3-none-any.whl
| Download URL | ubuntu_doctor-1.0.0-py3-none-any.whl |
|---|---|
| Size | 32.2 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
a4268e1e4db72e0421bf4e3a261310c992acbcaad6e840c519bfb75f56c57e7b
|
|
BLAKE2b-256 checksum How to use checksums |
88fde36a2837528bea53d4c2e5a1ef5f3eab868837321b2188801b6ba7083997
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.14
|
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 Jul 28, 2026.
Transparency log