English | Italiano
A small collection of paranoid, safety-first system utilities for Ubuntu and Linux.
The project focuses on inspection, diagnostics and developer-oriented maintenance, following a conservative philosophy:
- Read-only by default
- Explicit opt-in for state-changing operations
- Minimal dependencies
- Predictable CLI behaviour
The goal is to provide tools that solve everyday Linux problems without becoming a full system management framework.
This repository intentionally favors small, composable utilities over large automation suites.
Core principles:
- Safety first
- Read-only whenever possible
- Explicit confirmation before destructive actions
- Deterministic behaviour
- No hidden privilege escalation
- User-controlled scope
If a command changes system state, it should do so only after an explicit user request.
Clone the repository:
git clone https://github.com/gcomneno/ubuntu-system-tools
cd ubuntu-system-toolsThe recommended development installation creates symbolic links in
~/.local/bin, keeping the repository as the canonical source:
make install PREFIX=$HOME/.localMoving or deleting the cloned repository will break those links.
For autonomous executable copies instead:
make install-copy PREFIX=$HOME/.localSystem-wide installation always uses copies rather than links into a user checkout:
make install-systemUninstall a user-local installation:
make uninstall PREFIX=$HOME/.localThe installer refuses to replace or remove unrelated files. FORCE=1
is available only for an explicitly verified copy installation or
uninstallation.
Inspect recent security-related events:
security-health --since "24 hours ago"Run the local ClamAV scan against the usual personal directories:
security-clamav-scan --yesRun the weekly read-only health orchestration:
weekly-healthTranscribe a local audio message:
audio-transcribe --doctor
audio-transcribe --language it --allow-download message.oggBy default, model downloads are disabled. Once the selected model is available
locally, subsequent transcriptions do not require --allow-download.
Find where a dependency or identifier is used:
who-uses scan requestsPreview regenerable developer artifacts:
hdd_cleanupAudit removable development artifacts without deleting anything:
garbage-collector ~/Progetti --max-depth 4Inspect storage health, project elephants and optional growth against a checkpoint:
storage-check
storage-check --save-checkpoint "$HOME/.cache/ubuntu-system-tools/storage.env"
storage-check --checkpoint "$HOME/.cache/ubuntu-system-tools/storage.env"
storage-check --docker --ddev
storage-cleanup image IMAGE_REF_OR_ID
storage-cleanup volume VOLUME_NAME
storage-cleanup-proposalDiagnose a CUPS printer queue:
printer-doctor doctorList configured CUPS printers:
printer-doctor listRecover a disabled CUPS queue:
printer-doctor repairPreview a controlled package removal without changing the system:
safe-uninstall purge anydeskCreate a local configuration:
make init-config
nano ~/.config/ubuntu-system-tools/config.envLoad it:
set -a
source ~/.config/ubuntu-system-tools/config.env
set +aInspect and remove Ubuntu/Debian APT/dpkg packages with a complete, read-only plan before any mutation. Version 1 does not manage Snap, Flatpak, AppImage, Docker, language package managers, or manually installed software.
inspectandpurgeare read-only unless--applyis explicitly supplied- applied purges require root; the tool never invokes
sudointernally - generic discoveries are candidate-only and are never deleted or terminated
- exact residual cleanup and process/service handling require a trusted profile
- AnyDesk is the single trusted application profile in version 1
apt autoremoveis never run automatically
Inspect AnyDesk and preview its full removal plan:
safe-uninstall inspect anydesk
safe-uninstall purge anydeskApply that reviewed plan, using SUDO_USER as the target configuration owner:
sudo safe-uninstall purge anydesk --applyRoot can select another configuration owner explicitly with
--target-user USER.
Safely identifies regenerable developer artifacts such as
node_modules/, .venv/, target/ and common caches.
- Dry-run by default
--applyrequired for deletion- Intended for developer workspaces
Read-only scanner for removable development artifacts such as .venv/,
node_modules/, target/, Python caches and build output.
- Audit-only
- No deletion mode
- Reports size per artifact
- Prints total potentially reclaimable space
See the complete bilingual workflow guide: Storage workflow.
The storage orchestrator remains read-only by default. Optional --docker and
--ddev flags delegate to the dedicated storage-docker-audit and
storage-ddev-audit tools. Those audits classify evidence conservatively as
ACTIVE, INACTIVE_PROTECTED, STALE_CANDIDATE, or UNKNOWN; the
Docker-only and DDEV-only layers never promote an artifact to
STALE_CONFIRMED.
storage-docker-audit inspects Docker storage, container/image/volume
references, and BuildKit cache without running prune/remove operations.
storage-ddev-audit correlates the DDEV registry, project roots, Git worktree
evidence, and generated approot metadata. A stale generated path is reported
as DDEV_METADATA_STATE=STALE_PATH; it is not deletion authority.
storage-cleanup is a separate safe-by-default controlled-action tool. It does
not consume STALE_CANDIDATE as deletion authority and is intentionally not a
mutation mode of storage-check.
It accepts exactly one Docker image or volume target. The default invocation is
a read-only preview. Mutation requires the same exact target plus --apply.
Before an applied removal it resolves the target, rejects both running and stopped container references, and repeats the reference check immediately before invoking Docker. After a successful Docker removal it verifies that the exact target is absent.
Supported operations:
storage-cleanup image IMAGE_REF_OR_ID
storage-cleanup image IMAGE_REF_OR_ID --apply
storage-cleanup volume VOLUME_NAME
storage-cleanup volume VOLUME_NAME --apply
The tool does not run prune commands, remove containers, clear BuildKit cache,
perform DDEV deletion, invoke sudo, or infer mutation authority from an audit
classification.
storage-cleanup-proposal is a read-only bridge between Docker audit evidence
and explicit human review. It consumes only Docker STALE_CANDIDATE image and
volume records and produces a deterministic proposal manifest.
The proposal layer does not grant deletion authority:
STALE_CANDIDATE != STALE_CONFIRMED
PROPOSAL != AUTHORITY
For image candidates, the proposal uses the immutable Docker image ID rather than a mutable tag. Volume candidates use the exact volume name.
Each proposal includes only a preview command such as:
storage-cleanup image IMAGE_ID
storage-cleanup volume VOLUME_NAME
The proposal tool never emits --apply, never performs Docker or DDEV mutation,
never proposes BuildKit cache, and fails closed unless its Docker audit source
explicitly reports both STALE_CONFIRMED_COUNT=0 and
AUTOMATIC_DELETION=NO.
Its manifest always reports:
REVIEW_REQUIRED=YES
AUTHORITY=NO
AUTOMATIC_DELETION=NO
The tool runs as the current user, never invokes sudo, and requires the
storage-docker-audit helper plus standard sort, awk, and grep commands.
The delegated audit requires the user's normal Docker access.
Local Docker references and volume names may appear in diagnostic output, so proposal output should be reviewed before publication.
Read-only storage health and growth attribution for the local Ubuntu host.
- reports root filesystem usage and available space
- measures
$HOME,/varand the configured project root when fully readable - reports large project directories using configurable size/depth thresholds
- compares the current snapshot with an explicit checkpoint
--save-checkpointwrites only the explicitly selected checkpoint file- incomplete directory measurements are reported as
UNAVAILABLE - never deletes storage or performs automatic cleanup
The default project root is $PROJECTS_DIR when set, otherwise $HOME/Progetti.
Optional environment overrides are:
STORAGE_ROOT_WARN_PERCENT
STORAGE_PROJECT_ELEPHANT_MIN_BYTES
STORAGE_PROJECT_ELEPHANT_MAX_DEPTH
Exit status 1 means the inspection completed but root usage reached the
configured warning threshold. Exit status 2 means invalid input, malformed
checkpoint or operational failure.
Find where a package, dependency, binary or identifier is referenced.
Features:
- project scanning
- dependency inspection
- optional system inspection
- JSON output
- read-only operation
Inspect recent security-related events from the local system journal.
Features:
- sudo activity
- login/logout events
- kernel warnings
- optional output redaction
Safety-first ClamAV scanning for local, user-owned directories or an explicit full-system scan.
Features:
- read-only recursive scanning only
- default targets:
Downloads,DesktoporScrivania, andDocuments - explicit
--fullmode for/, with a prominent long-scan warning - per-user nonblocking lock to refuse concurrent scans cleanly
- user-controlled log location under XDG state by default
- no quarantine, deletion, freshclam, or automatic package management
Portable weekly orchestration for security-health, kernel-health, and
security-clamav-scan --yes.
Features:
- strict helper resolution with fail-closed ambiguity handling
- preserves component exit codes in the summary
- reports aggregate status
0,1,2,130, or143 - does not duplicate the owned logic of the component tools
Vendor-agnostic diagnostics and recovery for CUPS printer queues.
Features:
- inspect CUPS scheduler
- list configured printers
- inspect configured printers
- inspect queues
- detect disabled queues
- list pending jobs
- recover queues explicitly
- optional cancellation of stuck jobs after confirmation
Non-goals:
- cartridge cleaning
- nozzle checks
- vendor-specific maintenance
- proprietary driver management
Locally transcribe audio and voice messages through faster-whisper.
- Audio processing is local
- Model downloads are disabled by default
--allow-downloadis required to retrieve a missing model- Dependencies are never installed automatically
- Output is written to standard output unless
--output FILEis supplied --doctorreports the selected Python runtime and dependency availability
Check the runtime:
audio-transcribe --doctorTranscribe an Italian voice message using an already cached model:
audio-transcribe --language it message.oggExplicitly permit the first model download:
audio-transcribe --model small --language it --allow-download message.oggWrite the transcription to a file:
audio-transcribe --language it --output message.txt message.oggA dedicated environment can be prepared manually under
~/.local/share/ubuntu-system-tools/audio-transcribe/.venv. See
audio-transcribe --help-md for the exact commands.
The transcription may contain sensitive personal information. Review it before sharing or publishing it.
Bulk-convert ebook files for Kindle and other targets using Calibre's ebook-convert.
Calibre is required for real conversion. This tool is a safety-first wrapper around Calibre; it does not ship or install Calibre. Install it on the host before running a real conversion (not needed for --dry-run or --preflight):
sudo apt update
sudo apt install -y calibre
ebook-convert --versionBy default, the source format is EPUB, the target format is AZW3, the source directory is the current working directory, and the output directory is ./azw3.
The same converter is also available as bulk-ebook-convert, which accepts explicit --from and --to format options.
Dry-run from a directory containing EPUB files:
bin/bulk-epub-to-azw3 --dry-run
bin/bulk-ebook-convert --from epub --to azw3 --dry-runRun the real conversion:
bin/bulk-epub-to-azw3
bin/bulk-ebook-convert --from mobi --to epub --src ./mobiUse explicit source and output directories:
bin/bulk-epub-to-azw3 --src ./epub --out ./kindle --dry-run
bin/bulk-epub-to-azw3 --src ./epub --out ./kindle
bin/bulk-ebook-convert --from docx --to epub --src ./manuscripts --out ./epubWhen --out is omitted, the output directory defaults to ./<to> (for example ./epub or ./azw3).
Supported input formats: epub, mobi, azw, azw3, pdf, djvu, docx, doc, txt, html, htm, cbz, cbr.
Supported output formats: azw3, epub, mobi, pdf, txt, docx, kepub.
Curated conversion targets:
bin/bulk-ebook-convert --target kindle --src ./epub
bin/bulk-ebook-convert --target kobo --src ./epub
bin/bulk-ebook-convert --target archive --src ./mixed --out ./archive
bin/bulk-ebook-convert --target text --src ./epubTarget mapping: kindle → azw3, kobo → kepub, archive → epub, text → txt. --target cannot be combined with --to.
Export one library to multiple formats in a single run:
bin/bulk-ebook-convert --from epub --to azw3,epub,txt --src ./epub
bin/bulk-ebook-convert --from epub --to azw3,epub --src ./epub --out ./exportWith multiple --to formats, each target gets its own output tree (./azw3, ./epub, ... or OUT/azw3, OUT/epub, ...).
Unsupported formats are rejected before scanning. pdf and djvu sources emit quality warnings before conversion.
The tool validates EPUB files before conversion, preserves subdirectories, skips existing output files by default, and supports --force to overwrite existing output files.
Preflight EPUB metadata without converting:
bin/bulk-epub-to-azw3 --preflightThe preflight report includes the OPF package path, title, creator, language, identifier, cover detection, spine item count, and basic warnings for missing metadata.
Write a JSONL conversion manifest with checksums and tool versions:
bin/bulk-epub-to-azw3 --src ./epub --out ./kindle --manifest
bin/bulk-epub-to-azw3 --src ./epub --out ./kindle --dry-run --manifest ./reports/plan.jsonlEach manifest line records the source and output paths, status (converted, skipped, invalid, failed, or planned during dry-run), file sizes, SHA-256 checksums, timestamp, ebook-convert version, and skip or failure reasons when applicable.
Quarantine invalid or failed EPUB files for review without moving the originals:
bin/bulk-epub-to-azw3 --src ./epub --out ./kindle --quarantine ./review
bin/bulk-epub-to-azw3 --src ./epub --out ./kindle --quarantine ./review --quarantine-copyEach quarantined item is recorded under review/invalid/... or review/failed/... with a reason file, source path, optional symlink to the original EPUB, and conversion logs for failures.
Export Calibre debug-pipeline artifacts for failed conversions:
bin/bulk-epub-to-azw3 --src ./epub --out ./kindle --debug-failed ./debugOn failure, the tool reruns ebook-convert with --debug-pipeline and writes per-book debug output under ./debug/....
Control Kindle cover handling during conversion:
bin/bulk-epub-to-azw3 --src ./epub --out ./kindle --cover-policy prefer-metadata --dry-run
bin/bulk-epub-to-azw3 --src ./epub --out ./kindle --cover-policy remove-first-imagePolicies: keep (default), prefer-metadata (--prefer-metadata-cover), remove-first-image (--remove-first-image).
Choose a Kindle conversion profile for device-specific Calibre tuning:
bin/bulk-epub-to-azw3 --src ./epub --out ./kindle --profile kindle-paperwhite --dry-run
bin/bulk-epub-to-azw3 --src ./epub --out ./kindle --profile kindle-scribeProfiles: generic (default, no extra flags), kindle (--output-profile kindle), kindle-paperwhite (kindle_pw3), kindle-scribe (kindle_scribe), kindle-legacy (kindle + --mobi-file-type both). --profile controls Calibre output tuning; --target kindle selects the azw3 export format.
Enable conservative typography cleanup for messy EPUB HTML:
bin/bulk-epub-to-azw3 --src ./epub --out ./kindle --cleanup conservative --dry-runModes: off (default), conservative (--enable-heuristics). Opt-in only because heuristics can alter book structure.
Inject custom CSS for repeatable Kindle typography tweaks:
bin/bulk-epub-to-azw3 --src ./epub --out ./kindle --extra-css ./kindle.css --dry-runThe CSS file must exist before conversion starts. Paths with spaces are quoted in dry-run output.
Combine advanced options as needed (--profile, --cover-policy, --cleanup, --extra-css, --manifest, --quarantine, --debug-failed). Dry-run shows the resolved Calibre flags for each file.
Dependencies for bulk-epub-to-azw3 / bulk-ebook-convert:
| Dependency | When required | Install / verify |
|---|---|---|
Calibre (ebook-convert) |
Real conversion only | sudo apt install -y calibre then ebook-convert --version |
unzip, grep |
EPUB preflight and EPUB validation | sudo apt install -y unzip |
python3, sha256sum, date |
--manifest |
Usually preinstalled on Ubuntu |
Calibre is not required for --dry-run (planning output) or --preflight (metadata audit). The repository intentionally does not install system packages for you; see What this repository does NOT do.
sudo apt update
sudo apt install -y calibre unzip
ebook-convert --versionConvert a text-based PDF into EPUB using the safer two-step pipeline already formalized in docs/pdf2epub.md.
- extracts text with
pdftotext -layout - cleans the flow and promotes obvious headings
- delegates the final EPUB and table-of-contents generation to Calibre's
ebook-convert
pdf2epub "Document.pdf"
pdf2epub "Document.pdf" "Document-smart.epub"See the English guide in docs/pdf2epub.md and the Italian guide in docs/pdf2epub.it.md.
- Bash
- ripgrep (
rg) - python3
- Calibre (
ebook-convert) — required for real ebook conversion withbulk-epub-to-azw3/bulk-ebook-convert(not bundled; install separately) unzip— required for EPUB preflight/validation in the ebook converterfaster-whisper— required only foraudio-transcribe; install it manually in a dedicated Python virtual environment- systemd (optional)
- CUPS (only for
printer-doctor)
Every utility should be:
- small
- understandable
- scriptable
- deterministic
- safe by default
Whenever practical, tools expose self-contained documentation via
--help-md.
- No automatic installs
- No destructive actions by default
- No broad or unattended service orchestration
- No hidden privilege escalation
- No unsafe system modifications
If you are looking for an automation framework, this is intentionally not it.
Stable, intentionally small, and evolving slowly.
Contributions are welcome if they preserve the project's safety, simplicity and determinism.
who-uses scan <term> --json emits deterministic JSON with:
- no absolute paths
- no matched text
- projects-only scanning
- stable ordering
Exit codes:
0= no hits1= hits found2= operational error
These tools perform only local operations.
Some commands may display sensitive local information (usernames, hostnames, IP addresses, service names). Review output before sharing it publicly.
See POLICY.md.