Metadata-Version: 2.5
Name: lsdsk
Version: 1.3.0
Summary: See your disks and controllers, and what is wrong with how they are connected
Project-URL: Homepage, https://github.com/bitranox/lsdsk
Project-URL: Repository, https://github.com/bitranox/lsdsk.git
Project-URL: Issues, https://github.com/bitranox/lsdsk/issues
Author-email: bitranox <bitranox@gmail.com>
License: MIT
License-File: LICENSE
License-File: NOTICE
Keywords: cli,diagnostics,disk,hardware,nvme,pcie,sas,sata,smart,storage
Classifier: Environment :: Console
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Typing :: Typed
Requires-Python: >=3.11
Requires-Dist: lib-cli-exit-tools>=2.3.4
Requires-Dist: lib-layered-config>=5.6.2
Requires-Dist: lib-log-rich>=6.3.7
Requires-Dist: orjson>=3.12.0
Requires-Dist: pydantic>=2.13.5
Requires-Dist: rich-click>=1.9.9
Requires-Dist: rich>=15.0.0
Requires-Dist: textual>=8.2.8
Provides-Extra: dev
Requires-Dist: bandit>=1.9.4; extra == 'dev'
Requires-Dist: build>=1.6.1; extra == 'dev'
Requires-Dist: click>=8.5.0; extra == 'dev'
Requires-Dist: httpx2>=2.13.0; extra == 'dev'
Requires-Dist: hypothesis>=6.168.0; extra == 'dev'
Requires-Dist: import-linter>=2.15; extra == 'dev'
Requires-Dist: jaraco-context>=6.1.2; extra == 'dev'
Requires-Dist: pip-audit>=2.10.1; extra == 'dev'
Requires-Dist: pynacl>=1.6.2; extra == 'dev'
Requires-Dist: pyright[nodejs]>=1.1.414; extra == 'dev'
Requires-Dist: pytest-asyncio>=1.4.0; extra == 'dev'
Requires-Dist: pytest-cov>=7.1.0; extra == 'dev'
Requires-Dist: pytest>=9.1.1; extra == 'dev'
Requires-Dist: python-multipart>=0.0.32; extra == 'dev'
Requires-Dist: rtoml>=0.13.0; extra == 'dev'
Requires-Dist: ruff>=0.16.8; extra == 'dev'
Requires-Dist: twine>=7.0.0; extra == 'dev'
Requires-Dist: urllib3>=2.8.0; extra == 'dev'
Requires-Dist: virtualenv>=21.9.0; extra == 'dev'
Requires-Dist: wheel>=0.48.0; extra == 'dev'
Description-Content-Type: text/markdown

# lsdsk

**English** | [Deutsch](https://github.com/bitranox/lsdsk/blob/main/de/README.md)

<!-- Badges -->
[![CI](https://github.com/bitranox/lsdsk/actions/workflows/default_cicd_public.yml/badge.svg)](https://github.com/bitranox/lsdsk/actions/workflows/default_cicd_public.yml)
[![CodeQL](https://github.com/bitranox/lsdsk/actions/workflows/codeql.yml/badge.svg)](https://github.com/bitranox/lsdsk/actions/workflows/codeql.yml)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
[![Open in Codespaces](https://img.shields.io/badge/Codespaces-Open-blue?logo=github&logoColor=white&style=flat-square)](https://codespaces.new/bitranox/lsdsk?quickstart=1)
[![PyPI](https://img.shields.io/pypi/v/lsdsk.svg)](https://pypi.org/project/lsdsk/)
[![PyPI - Downloads](https://img.shields.io/pypi/dm/lsdsk.svg)](https://pypi.org/project/lsdsk/)
[![Code Style: Ruff](https://img.shields.io/badge/Code%20Style-Ruff-46A3FF?logo=ruff&labelColor=000)](https://docs.astral.sh/ruff/)
[![codecov](https://codecov.io/gh/bitranox/lsdsk/graph/badge.svg?token=JKJR0XzLus)](https://codecov.io/gh/bitranox/lsdsk)
[![Maintainability](https://qlty.sh/gh/bitranox/projects/lsdsk/maintainability.svg)](https://qlty.sh/gh/bitranox/projects/lsdsk)
[![security: bandit](https://img.shields.io/badge/security-bandit-yellow.svg)](https://github.com/PyCQA/bandit)

lsdsk is a storage diagnostic for Linux and Windows: it groups every drive under the
controller and the PCIe path it hangs off, reads what the ports and the drives can do and what
they actually negotiated, reads SMART data and error counters, and recommends what to act on.

c't Magazin covered it on 17 September 2026, in German:
[Kommandozeilentool lsdsk: Performance-Engpässe bei SSDs und Controllern finden](https://www.heise.de/ratgeber/Kommandozeilentool-lsdsk-Performance-Engpaesse-bei-SSDs-und-Controllern-finden-11440011.html).

Ten drives, three controllers, a chipset and a riser between them and the CPU. The machine
boots fine, and nothing on it tells you that one card negotiated x1 in an x8 slot, that two
SSDs share a link, or that the free port you were about to fill hangs off an uplink that is
already full. A storage server rarely fails outright. It runs quietly for years with a
shortfall that is easy to fix, and the values that would explain it are spread across sysfs, a
set of ioctls and the mainboard manual.

lsdsk starts no subprocesses and makes no network requests: every value it prints was read
directly, from sysfs and direct ioctls on Linux and from SetupAPI and DeviceIoControl on
Windows.

## QUICKSTART

The command below needs `uv` and nothing else; if `uv` is not installed yet,
[INSTALL.md](https://github.com/bitranox/lsdsk/blob/main/INSTALL.md#easiest-install-and-run-with-uv) documents the one-line installer for
Linux, macOS and Windows.

For full information run `lsdsk` as root or Administrator. Without those rights you lose SMART
wear, the error counters, PCIe connector detection and the SATA controllers' port count. The
details are in [INSTALL.md](https://github.com/bitranox/lsdsk/blob/main/INSTALL.md#what-needs-root).

The usual invocation is `uvx lsdsk@latest` - uv then installs the newest version in a virtual
environment. The rest of this document writes the short form `lsdsk` for readability.

```bash
# run as Administrator or root for full information 
uvx lsdsk@latest          # lsdsk TUI
uvx lsdsk@latest report   # get a printed report
uvx lsdsk@latest --help   # get further help
```

`uvx lsdsk@latest` opens an interactive view at a terminal, with a page per
topic; piped or redirected it prints the same data as one page: the mainboard,
what is wrong, the controller tree, every disk's identity, wear and error
counters, every SMART attribute, the PCIe slots, and each finding with its
reasoning.

## The TUI

Number keys switch between the pages, `Tab` cycles, and every page is also a subcommand, so `lsdsk health` prints exactly what page 4 shows.

![The lsdsk interactive view: eight pages, the tree density cycling, the detail panel, and a table being scrolled](https://raw.githubusercontent.com/bitranox/lsdsk/main/docs/media/lsdsk-demo.gif)

Six of the eight pages carry a cursor, and a panel under the table gives the
detail: every value the row had no column for, and the findings that go with it.
[PAGES.md](https://github.com/bitranox/lsdsk/blob/main/PAGES.md) describes all eight pages in detail.

Through a pipe, into a file, or with the command `lsdsk report`, the program
prints text instead, most important findings first.
[REPORT.md](https://github.com/bitranox/lsdsk/blob/main/REPORT.md) documents that report.

## Privileges

`lsdsk` runs unprivileged too. Topology, PCIe link state, SATA capability and
negotiated speed, SAS phy rates, capacity, controller firmware and NVMe
temperature all read without elevated rights.

Four things do need root or Administrator:

- **SMART attributes and wear.**
- **The error counters, so `trend` and `record`.**
- **PCIe slot numbers and whether a port is a real connector.**
- **The AHCI capability register.**

Inside an LXC or Proxmox container these values cannot be read even with
elevated rights.

## lsdsk ships a skill for Claude Code

The hard part of a storage report is not reading it, it is knowing which findings
deserve action. lsdsk ships that judgement as a Claude Code skill, so an agent
reading the output reaches the same conclusions a practised admin would.

```
# in claude code
/plugin marketplace add bitranox/lsdsk
/plugin install lsdsk
```

The skill shows and explains what the tool cannot: that a CRC count is the cable
and never the drive, that a wear percentage means nothing without the drive's
own threshold, that a controller capped by the board has two opposite remedies
depending on whether a faster port exists and is merely occupied, and that a
slot number is matched against the mainboard manual because no readable source
gives the form factor. `lsdsk` can also export every value as JSON, and the
skill can then interpret that data on another machine. Nobody wants an agent
running on the server itself.

## Install

```bash
uvx lsdsk@latest       # run without installing
uv tool install lsdsk  # install for repeated use, in its own venv
pip install lsdsk      # if you prefer the old way
```

Python 3.11 or newer, Linux or Windows. It shells out to nothing: no
`smartmontools`, no `nvme-cli`, no `lspci`, no subprocess of any kind, and no
network access at any point. Its own Python dependencies are declared in
`pyproject.toml`.

From the hardware `lsdsk` reads only a controller's numeric identifiers, not its
name. The PCI name database therefore ships with it. That is why a controller
reads the same on Linux and on Windows; lsdsk does not quote the localised
device names Windows carries. See `NOTICE` for that database's licence.

## How lsdsk works

Linux reads sysfs and issues `SG_IO` ATA passthrough and NVMe admin ioctls
directly. A SATA port's own speed comes from the AHCI controller's capability
register. Windows uses `SetupAPI` and `DeviceIoControl` through `ctypes`, with
no WMI and no PowerShell. Both platforms receive the same ATA IDENTIFY, ATA
SMART and NVMe structures, so a single set of decoders serves both and is tested
against captures from real hardware on every supported operating system.

Every command lsdsk issues is a read. It never writes to a device or a controller.

## Documentation

| Document                                                                                                                   | What it covers                                                                       |
|----------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------|
| [PAGES.md](https://github.com/bitranox/lsdsk/blob/main/PAGES.md)                                                           | The eight pages and the key bindings                                                 |
| [REPORT.md](https://github.com/bitranox/lsdsk/blob/main/REPORT.md)                                                         | The one-page report                                                                  |
| [COMMANDS.md](https://github.com/bitranox/lsdsk/blob/main/COMMANDS.md)                                                     | Every command and global option, the JSON envelope, and the exit codes               |
| [FINDINGS.md](https://github.com/bitranox/lsdsk/blob/main/FINDINGS.md)                                                     | What it reports, and what evidence each rule needs                                   |
| [WHY.md](https://github.com/bitranox/lsdsk/blob/main/WHY.md)                                                               | The problem it was written for, and the two cases easiest to get wrong without it    |
| [INSTALL.md](https://github.com/bitranox/lsdsk/blob/main/INSTALL.md)                                                       | Installing it, and what works unprivileged versus what needs root                    |
| [CONFIG.md](https://github.com/bitranox/lsdsk/blob/main/CONFIG.md)                                                         | Every configuration key, the layered sources, and the env-var forms                  |
| [DEVELOPMENT.md](https://github.com/bitranox/lsdsk/blob/main/DEVELOPMENT.md)                                               | Working on lsdsk: the gate, the test lanes, capturing a fixture                      |
| [CONTRIBUTING.md](https://github.com/bitranox/lsdsk/blob/main/CONTRIBUTING.md)                                             | How to propose a change                                                              |
| [SECURITY.md](https://github.com/bitranox/lsdsk/blob/main/SECURITY.md)                                                     | Reporting a vulnerability                                                            |
| [CHANGELOG.md](https://github.com/bitranox/lsdsk/blob/main/CHANGELOG.md)                                                   | What changed, and when                                                               |
| [docs/systemdesign/module_reference.md](https://github.com/bitranox/lsdsk/blob/main/docs/systemdesign/module_reference.md) | Every module, the layer rule, the CLI commands and the exit codes                    |
| [ai-transparency.md](https://github.com/bitranox/lsdsk/blob/main/ai-transparency.md)                                       | Where an AI assistant was used, what was verified on real hardware, and what was not |
| [ai-stance.md](https://github.com/bitranox/lsdsk/blob/main/ai-stance.md)                                                   | Why the project takes that position                                                  |

## Licence

MIT.
