Metadata-Version: 2.4
Name: ubuntu-doctor
Version: 1.0.0
Summary: Read-only diagnostic CLI for Ubuntu systems, with explained findings and stable JSON output.
Project-URL: Homepage, https://github.com/david-oliveira-dev/ubuntu-doctor
Project-URL: Repository, https://github.com/david-oliveira-dev/ubuntu-doctor
Project-URL: Changelog, https://github.com/david-oliveira-dev/ubuntu-doctor/blob/main/CHANGELOG.md
Author-email: David Oliveira <davidoliveira.devbr@gmail.com>
License: MIT License
        
        Copyright (c) 2026 David Oliveira
        
        Permission is hereby granted, free of charge, to any person obtaining a copy
        of this software and associated documentation files (the "Software"), to deal
        in the Software without restriction, including without limitation the rights
        to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
        copies of the Software, and to permit persons to whom the Software is
        furnished to do so, subject to the following conditions:
        
        The above copyright notice and this permission notice shall be included in all
        copies or substantial portions of the Software.
        
        THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
        IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
        FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
        AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
        LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
        OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
        SOFTWARE.
License-File: LICENSE
Keywords: cli,devops,diagnostics,linux,sysadmin,systemd,ubuntu
Classifier: Development Status :: 5 - Production/Stable
Classifier: Environment :: Console
Classifier: Intended Audience :: System Administrators
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: POSIX :: Linux
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: System :: Systems Administration
Classifier: Typing :: Typed
Requires-Python: >=3.11
Requires-Dist: psutil>=5.9
Requires-Dist: pydantic>=2.7
Requires-Dist: rich>=13.7
Requires-Dist: typer>=0.12
Description-Content-Type: text/markdown

# ubuntu-doctor

> Read-only diagnostic CLI for Ubuntu systems, with explained findings and stable JSON output.

[![CI](https://github.com/david-oliveira-dev/ubuntu-doctor/actions/workflows/ci.yml/badge.svg)](https://github.com/david-oliveira-dev/ubuntu-doctor/actions/workflows/ci.yml)
![License: MIT](https://img.shields.io/badge/license-MIT-green)

## 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 `systemd` units
- 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`](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.

```mermaid
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](https://pipx.pypa.io/):

```bash
pipx install ubuntu-doctor
```

From a clone, using [uv](https://docs.astral.sh/uv/):

```bash
uv sync
uv run ubuntu-doctor --help
```

## Usage

```bash
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):

```text
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):

```toml
[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

```bash
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/`](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 --audit` needs
  the dpkg lock, which requires privilege. This is expected: the check degrades to
  `UNKNOWN` rather than failing. Run `sudo dpkg --audit` yourself to check.
- **Listening ports show no process** — `ss` cannot name processes owned by other users
  without privilege. The port is still listed; only the owner is hidden.
- **`command not found` for a check** — on a minimal system `systemctl`, `ss` or `apt` may
  be absent; that check reports `UNKNOWN` and 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 `linuxfacts` library.

## 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](LICENSE).

## Contact

David Oliveira · davidoliveira.devbr@gmail.com
