duvis 0.1.3

Disk usage visualizer for both AI and humans
Documentation
  • 🤖 AI-friendly — hierarchical JSON with size, category, and freshness
  • 🖥️ Human-friendly — browser UI with treemap, sunburst, and list views
  • Fast — parallel directory scanning powered by rayon
  • 🛡️ Read-only by design — never deletes, never recommends deletions
  • 🌐 Cross-platform — macOS, Linux, Windows

duvis (pronounced /ˈduːvɪs/, like "doo-vis") is a fast, read-only disk usage analyzer that helps both AI agents and humans understand what's filling their disk. Point it at any directory and it gives you two ways to look at it:

  • A CLI that emits a structured JSON tree, a category summary, or a colorized terminal tree — easy to pipe into agents, scripts, or jq.
  • A browser UI (React + d3) with treemap, sunburst, and list views, color-coded by category, so you can drill in visually.

Every entry is auto-tagged by category — cache, build, log, vcs, media, ide — so "what's eating my disk?" shows up at a glance. duvis only shows you the picture; deleting is your call to make with your own tools.

Install

cargo install duvis

Or build from source:

git clone https://github.com/yamadashy/duvis.git
cd duvis
cargo install --path .

Usage

# Tree view of the current directory
duvis

# Limit depth and show top N entries
duvis ~/projects --depth 2 --top 10

# Category-aware summary (cache / build / log / media / vcs / ide / other)
duvis ~/projects --analyze

# Structured JSON output (for AI agents and scripts)
duvis ~/projects --json

# Open browser UI with an interactive treemap
duvis ~/projects --ui

Options

Flag Description
-d, --depth <N> Maximum depth to display
-n, --top <N> Show only the top N entries by size
--json Output as JSON
--analyze Show a per-category size summary
--ui Open browser UI with treemap visualization
--port <PORT> Port for UI server (default: 7515, see below). Falls back to a free port if busy.
--sort <size|name> Sort order (default: size)
--reverse Reverse sort order
--hardlinks <count-once|count-each> How to attribute bytes to hardlinked files (default: count-once, matches du).

--json / --analyze / --ui are mutually exclusive; pass at most one. With none, the default tree view is shown.

Output examples

Tree

project (438.9 MB)
├── target/  [build] 438.8 MB
├── .git/    [vcs]    54.7 KB
├── src/              24.5 KB
└── Cargo.toml        418 B

Analyze

Total: 438.9 MB

Category Summary:
  build      438.9 MB  100%  1 items

JSON

{
  "name": "project",
  "size": 460195536,
  "size_human": "438.9 MB",
  "is_dir": true,
  "category": "build",
  "modified_days_ago": 0,
  "children": [
    { "name": "target", "size": 460091645, "category": "build", ... }
  ]
}

Categories

duvis classifies entries into a small core vocabulary that always appears in the legend, plus a handful of extended categories that show up only when something matches them. Core stays compact for typical project trees; extended pops into view when relevant (e.g. a model_cache row appears on an AI dev machine, an installer row appears in ~/Downloads).

Core

  • cache — package and tool caches (node_modules/, .cache/, __pycache__/, .cargo/, ...)
  • build — build artifacts (target/, dist/, build/, .next/, ...)
  • log — log files (*.log, logs/, ...)
  • media — images, video, audio
  • vcs — version control metadata (.git/, ...)
  • ide — IDE/editor metadata (.idea/, .vscode/, ...)
  • other — everything else

Extended (shown only when present)

  • archive — compressed bundles (*.zip, *.tar.gz, *.7z, *.zst, ...)
  • installer — install packages (*.dmg, *.pkg, *.exe, *.deb, *.AppImage, ...)
  • vm_image — virtual machine disk images (*.vdi, *.vmdk, *.qcow2, OrbStack's data.img.raw, ...)
  • model_cache — local AI model stores (.ollama/, .lmstudio/, .huggingface/)
  • backup — backups (Time Machine, *.bak, *.backup, *.old)

Categories are assigned by directory or file name. Once a directory is classified as anything other than other, everything inside it inherits that category — because that directory is the natural grouping unit (a node_modules is a single thing, not a heap of unrelated files). The outermost named ancestor wins, so a project root that happens to contain a giant node_modules is not itself classified as cache.

How sizes are measured

On Unix, duvis reports the bytes a file actually occupies on disk (st_blocks × 512, the same default as du). Sparse files like VM images — for example OrbStack's data.img.raw — show their real footprint, not the multi-terabyte logical size you'd get from ls -l.

Hardlinked files are counted once per inode by default, also matching du — a 1 GB file with two hardlinks contributes 1 GB to the total, not 2 GB. The first path to reach the inode reports the bytes; later links report 0. Pass --hardlinks count-each to opt out and have every link contribute its full size (matching tools that don't dedupe by inode).

Windows falls back to apparent size for now and does not dedupe hardlinks.

Why port 7515?

In the spirit of Vite's 5173 (SITE/VITE written with Roman numerals + leet — V=5, I=1, T=7, E=3), duvis defaults to 7515: drop D (it's basically a closed O), tilt U on its side and it's a 7, V=5 (Roman), I=1, S=5 (leet). Not assigned to anything in the IANA registry, far enough from the 8080/3000/5173 clash zones, and if it's still busy on your machine duvis quietly falls back to a free OS-assigned port.

License

MIT © Kazuki Yamada