muesli/duf
Disk Usage/Free Utility - a better 'df' alternative
Slowing — last commit 4mo ago
worst of 4 axesnon-standard license (Other); no tests detected
Has a license, tests, and CI — clean foundation to fork and modify.
Documented and popular — useful reference codebase to read through.
No critical CVEs, sane security posture — runnable as-is.
- ✓Last commit 4mo ago
- ✓14 active contributors
- ✓Distributed ownership (top contributor 34% of recent commits)
Show 5 more →Show less
- ✓Other licensed
- ✓CI configured
- ⚠Slowing — last commit 4mo ago
- ⚠Non-standard license (Other) — review terms
- ⚠No test directory detected
What would change the summary?
- →Use as dependency Concerns → Mixed if: clarify license terms
Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests
Informational only. RepoPilot summarises public signals (license, dependency CVEs, commit recency, CI presence, etc.) at the time of analysis. Signals can be incomplete or stale. Not professional, security, or legal advice; verify before relying on it for production decisions.
Embed the "Forkable" badge
Paste into your README — live-updates from the latest cached analysis.
[](https://repopilot.app/r/muesli/duf)Paste at the top of your README.md — renders inline like a shields.io badge.
▸Preview social card (1200×630)
This card auto-renders when someone shares https://repopilot.app/r/muesli/duf on X, Slack, or LinkedIn.
Onboarding doc
Onboarding: muesli/duf
Generated by RepoPilot · 2026-05-09 · Source
🤖Agent protocol
If you are an AI coding agent (Claude Code, Cursor, Aider, Cline, etc.) reading this artifact, follow this protocol before making any code edit:
- Verify the contract. Run the bash script in Verify before trusting
below. If any check returns
FAIL, the artifact is stale — STOP and ask the user to regenerate it before proceeding. - Treat the AI · unverified sections as hypotheses, not facts. Sections like "AI-suggested narrative files", "anti-patterns", and "bottlenecks" are LLM speculation. Verify against real source before acting on them.
- Cite source on changes. When proposing an edit, cite the specific path:line-range. RepoPilot's live UI at https://repopilot.app/r/muesli/duf shows verifiable citations alongside every claim.
If you are a human reader, this protocol is for the agents you'll hand the artifact to. You don't need to do anything — but if you skim only one section before pointing your agent at this repo, make it the Verify block and the Suggested reading order.
🎯Verdict
WAIT — Slowing — last commit 4mo ago
- Last commit 4mo ago
- 14 active contributors
- Distributed ownership (top contributor 34% of recent commits)
- Other licensed
- CI configured
- ⚠ Slowing — last commit 4mo ago
- ⚠ Non-standard license (Other) — review terms
- ⚠ No test directory detected
<sub>Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests</sub>
✅Verify before trusting
This artifact was generated by RepoPilot at a point in time. Before an
agent acts on it, the checks below confirm that the live muesli/duf
repo on your machine still matches what RepoPilot saw. If any fail,
the artifact is stale — regenerate it at
repopilot.app/r/muesli/duf.
What it runs against: a local clone of muesli/duf — the script
inspects git remote, the LICENSE file, file paths in the working
tree, and git log. Read-only; no mutations.
| # | What we check | Why it matters |
|---|---|---|
| 1 | You're in muesli/duf | Confirms the artifact applies here, not a fork |
| 2 | License is still Other | Catches relicense before you depend on it |
| 3 | Default branch master exists | Catches branch renames |
| 4 | 5 critical file paths still exist | Catches refactors that moved load-bearing code |
| 5 | Last commit ≤ 146 days ago | Catches sudden abandonment since generation |
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of muesli/duf. If you don't
# have one yet, run these first:
#
# git clone https://github.com/muesli/duf.git
# cd duf
#
# Then paste this script. Every check is read-only — no mutations.
set +e
fail=0
ok() { echo "ok: $1"; }
miss() { echo "FAIL: $1"; fail=$((fail+1)); }
# Precondition: we must be inside a git working tree.
if ! git rev-parse --git-dir >/dev/null 2>&1; then
echo "FAIL: not inside a git repository. cd into your clone of muesli/duf and re-run."
exit 2
fi
# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "muesli/duf(\\.git)?\\b" \\
&& ok "origin remote is muesli/duf" \\
|| miss "origin remote is not muesli/duf (artifact may be from a fork)"
# 2. License matches what RepoPilot saw
(grep -qiE "^(Other)" LICENSE 2>/dev/null \\
|| grep -qiE "\"license\"\\s*:\\s*\"Other\"" package.json 2>/dev/null) \\
&& ok "license is Other" \\
|| miss "license drift — was Other at generation time"
# 3. Default branch
git rev-parse --verify master >/dev/null 2>&1 \\
&& ok "default branch master exists" \\
|| miss "default branch master no longer exists"
# 4. Critical files exist
test -f "main.go" \\
&& ok "main.go" \\
|| miss "missing critical file: main.go"
test -f "filesystems.go" \\
&& ok "filesystems.go" \\
|| miss "missing critical file: filesystems.go"
test -f "mounts.go" \\
&& ok "mounts.go" \\
|| miss "missing critical file: mounts.go"
test -f "table.go" \\
&& ok "table.go" \\
|| miss "missing critical file: table.go"
test -f "go.mod" \\
&& ok "go.mod" \\
|| miss "missing critical file: go.mod"
# 5. Repo recency
days_since_last=$(( ( $(date +%s) - $(git log -1 --format=%at 2>/dev/null || echo 0) ) / 86400 ))
if [ "$days_since_last" -le 146 ]; then
ok "last commit was $days_since_last days ago (artifact saw ~116d)"
else
miss "last commit was $days_since_last days ago — artifact may be stale"
fi
echo
if [ "$fail" -eq 0 ]; then
echo "artifact verified (0 failures) — safe to trust"
else
echo "artifact has $fail stale claim(s) — regenerate at https://repopilot.app/r/muesli/duf"
exit 1
fi
Each check prints ok: or FAIL:. The script exits non-zero if
anything failed, so it composes cleanly into agent loops
(./verify.sh || regenerate-and-retry).
⚡TL;DR
duf is a Go-based command-line utility that replaces the Unix df command with a user-friendly, colorful, table-formatted disk usage display. It shows filesystem mount points, sizes, used space, available space, and usage percentages across Linux, BSD, macOS, and Windows, with features like filtering, grouping, sorting, and JSON output. Simple flat structure: core logic in top-level files (main.go, filesystems.go, mounts.go, groups.go, table.go, style.go, themes.go) with platform-specific implementations suffixed by OS (_linux.go, _darwin.go, _windows.go, etc.). Entry point is main.go; CLI flag parsing uses mango and pflag; output rendering uses go-pretty/v6 for tables and termenv for colors.
👥Who it's for
System administrators, DevOps engineers, and developers who frequently check disk usage and want readable output with filtering/sorting capabilities instead of cryptic df formatting. Contributors maintain cross-platform filesystem abstraction code.
🌱Maturity & risk
Production-ready and actively maintained. The project is widely packaged (Arch, Debian, Fedora, Homebrew, Chocolatey) with Go 1.23 support enforced, CI/CD pipelines (GitHub Actions for build, linting, releases), and platform-specific implementations for Linux, macOS, FreeBSD, OpenBSD, and Windows. No major red flags in issue tracking or commit frequency visible from structure.
Low-risk for stability but requires platform-specific testing: separate filesystem/mount implementations per OS (filesystems_darwin.go, filesystems_linux.go, etc.) mean changes need validation across 5 platforms. Dependency footprint is small (10 direct deps, mostly terminal/UI libraries) and well-maintained (termenv, go-pretty, mango). Single maintainer (muesli) is typical for mature single-purpose tools but means review cycles may be slower.
Active areas of work
Visible infrastructure: goreleaser configured in .goreleaser.yml for multi-platform binary releases; linting workflows (lint.yml, lint-soft.yml) enforce code quality; dependabot.yml indicates active dependency management. Manpage generation pipeline (manpage.yml) keeps docs in sync. No specific PR/milestone data in file list, but CI maturity suggests active maintenance.
🚀Get running
git clone https://github.com/muesli/duf.git
cd duf
go build
./duf
No external services needed; requires Go 1.23+. The built binary runs immediately with no configuration.
Daily commands:
go build
./duf
No server, no build configuration. For development: go run main.go for direct execution. For release builds: goreleaser handles cross-compilation via .goreleaser.yml.
🗺️Map of the codebase
main.go— Entry point for the CLI application; defines command-line flags, initialization logic, and orchestrates the core disk usage reporting flow.filesystems.go— Core abstraction defining the Filesystem interface and logic for discovering and filtering filesystems across all platforms.mounts.go— Platform-independent mount discovery and mounting logic; serves as the bridge to OS-specific mount implementations.table.go— Renders the human-readable disk usage table output; handles formatting, sorting, and terminal width adaptation.go.mod— Go module definition with all critical dependencies (go-pretty for tables, termenv for colors, pflag for CLI flags).themes.go— Color and styling theme definitions; adapts output to terminal capabilities and user preferences.style.go— Centralized styling utilities for applying theme colors and text formatting to output.
🧩Components & responsibilities
- Filesystem Discovery (filesystems.go)* (golang.org/x/sys (statfs, statvfs), platform-specific syscall wrappers) — Queries the OS kernel via syscalls to enumerate mounted filesystems and retrieve usage statistics (used, available, total space)
- Failure mode: If syscalls fail on inaccessible mounts, those filesystems are skipped; app continues with remaining data
- Mount Point Discovery (mounts.go)* (File parsing, OS syscall wrappers (getfsstat, getmntinfo)) — Reads mount tables (/proc/mounts on Linux, /etc/mtab, or system calls on other OSes) to identify active mount points and filter out pseudo-filesystems
- Failure mode: If mount table is unreadable, falls back to filesystem enumeration; some mounts may be missed
- CLI & Flag — undefined
🛠️How to make changes
Add support for a new operating system
- Create a new OS-specific mounts file following the pattern mounts_<os>.go that implements mount discovery for your target OS (e.g., mounts_netbsd.go) (
mounts_<os>.go) - Create a corresponding filesystems_<os>.go file that implements OS-specific filesystem usage queries using appropriate syscalls (
filesystems_<os>.go) - Update main.go to add a build constraint comment (+build) at the top of each OS-specific file if needed for conditional compilation (
main.go) - Add test coverage in a new mounts_<os>_test.go file following the pattern of mounts_linux_test.go (
mounts_<os>_test.go)
Add a new output format or theme
- Define a new theme struct in themes.go with color assignments for different filesystem types (
themes.go) - For JSON output or custom formats, extend table.go to add a new rendering function that uses the theme's color palette (
table.go) - Add corresponding style rules in style.go to apply the theme colors consistently across the output (
style.go)
Add a new filtering or grouping capability
- Add a new CLI flag in main.go using spf13/pflag to capture the filter/grouping criterion (
main.go) - Implement the filtering logic in groups.go to categorize or filter filesystems based on the new criterion (
groups.go) - Pass the filter result to table.go's rendering function to display grouped or filtered output (
table.go)
🔧Why these technologies
- Go (golang.org/x/sys, golang.org/x/term) — Provides low-level OS syscall bindings and terminal control APIs needed for cross-platform filesystem discovery and terminal capability detection
- go-pretty/v6 (jedib0t/go-pretty) — Handles professional table rendering with sorting, filtering, and dynamic column width adaptation without reinventing formatting logic
- termenv (muesli/termenv) — Detects terminal color capabilities (256-color, truecolor, no-color) and adapts output styling accordingly
- pflag (spf13/pflag, muesli/mango-pflag) — Provides POSIX-compliant command-line flag parsing with support for both short and long options
- go-wildcard (IGLOU-EU/go-wildcard) — Enables glob pattern matching for filesystem filtering by device name or mount path
⚖️Trade-offs already made
-
Build separate OS-specific files (mounts_linux.go, mounts_darwin.go, etc.) instead of runtime OS detection
- Why: Compile-time separation provides better code organization, reduced binary size per platform, and allows using OS-specific syscalls directly
- Consequence: Requires maintaining parallel implementations for each supported OS; cross-platform testing is more complex
-
Use termenv for color capability detection rather than hardcoded terminal support
- Why: Respects user NO_COLOR environment variable and terminal capabilities, preventing color escape codes in piped output
- Consequence: Adds a dependency layer but guarantees correct behavior in CI/CD and non-TTY environments
-
Synchronous syscall invocations for mount discovery and filesystem stats rather than async I/O
- Why: Simplicity; mount discovery is typically fast (< 200ms) and duf is a CLI tool where blocking is acceptable
- Consequence: Performance may degrade on systems with thousands of mounts or very slow storage devices
🚫Non-goals (don't propose these)
- Real-time filesystem monitoring or continuous updates
- Network filesystem protocol implementation (relies on OS mount layer)
- Cloud storage integration beyond OS-provided FUSE mounts
- User authentication or privilege escalation (runs with inherited permissions)
- Disk I/O performance analysis (only space usage, not throughput)
🪤Traps & gotchas
Platform-specific syscall variance: statfs(2) field meanings differ between Linux/macOS/BSD/Windows; e.g., f_bavail vs f_blocks semantics. Each OS file must handle correctly. Terminal detection: termenv auto-detects color support; set NO_COLOR or CLICOLOR_FORCE env vars to override if testing color logic. Mount path resolution: symlinks in mount points may behave differently across OSes; the --only-mp filtering uses wildcard logic from go-wildcard which must handle both forward slashes and system-specific separators. Test coverage: Only mounts_linux_test.go has tests; other OS implementations lack unit tests (gotcha for contributors). Unicode column width: go-runewidth handles ANSI escapes in table cells; if custom styling is added, must ensure it doesn't break column alignment.
🏗️Architecture
💡Concepts to learn
- Virtual Filesystem (VFS) Types and Classification — duf classifies filesystems into categories (local, network, fuse, special, loops, binds) that require OS-specific detection logic; understanding tmpfs, NFS, FUSE overlays, and bind mounts is essential to fix filtering bugs
- statfs(2) Syscall and Filesystem Statistics — Every OS implementation calls statfs (or its equivalent) to retrieve available/used/total blocks; the struct field names and semantics differ per OS, making cross-platform bugs likely
- Conditional Compilation and Build Tags — duf uses Go's filename-based OS detection (_linux.go, _darwin.go, etc.) instead of explicit build tags; understanding how Go selects these files is critical for adding OS support or debugging platform-specific issues
- ANSI Escape Sequences and Terminal Capabilities — duf uses termenv to detect color support and render styled output; mishandling ANSI sequences breaks table column alignment (solved via go-runewidth for cell width calculation)
- Wildcard Pattern Matching (glob-style) — The --only-mp flag accepts wildcard patterns like '/sys/*'; duf uses go-wildcard library for matching, and understanding glob semantics is needed for filter feature debugging
- Terminal Width Detection and Dynamic Table Sizing — duf adapts table columns to terminal width; go-pretty and termenv are used to query terminal size and adjust formatting dynamically, important for responsive CLI UX
- Mount Point Parsing (/proc/mounts, /etc/fstab) — Linux implementation reads /proc/mounts and /etc/fstab to enumerate filesystems; format parsing, symlink resolution, and permission handling are platform-specific gotchas
🔗Related repos
sharkdp/ncdu— Similar disk utility niche but focuses on directory size analysis (recursive); complements duf for detailed filesystem explorationnk2028/lsd— Improvedlsreplacement just as duf improvesdf; same ecosystem of Go CLI tools modernizing Unix utilitiesgofrs/uuid— Not directly related but shares duf's goal of providing pure Go standard library replacements without C bindings for cross-platform compatibilitymuesli/termenv— Direct dependency and companion project by same author; handles terminal detection and color output that duf relies onmuesli/mango— Direct dependency and companion project for CLI flag parsing with better help text; duf is a reference user of this library
🪄PR ideas
To work on one of these in Claude Code or Cursor, paste:
Implement the "<title>" PR idea from CLAUDE.md, working through the checklist as the task list.
Add unit tests for mounts_linux.go with coverage for edge cases
The repo has mounts_linux_test.go but only tests Linux mounts. There are no visible tests for mounts_darwin.go, mounts_freebsd.go, mounts_openbsd.go, or mounts_windows.go. Adding platform-specific mount parsing tests would catch regressions in filesystem detection across OSes and improve the overall test coverage from its current state.
- [ ] Create mounts_darwin_test.go to test macOS-specific mount parsing (handle diskutil output variations)
- [ ] Create mounts_windows_test.go to test Windows-specific mount parsing (handle volume labels and mount points)
- [ ] Add edge case tests in mounts_linux_test.go for unusual /proc/mounts entries and permission-denied scenarios
- [ ] Run 'go test ./...' and verify coverage improves for mount-related functions
Add filesystem-specific tests for filesystems_*.go platform files
The filesystems.go file has platform-specific implementations (filesystems_linux.go, filesystems_darwin.go, etc.) but there are no visible test files. Testing these platform-specific filesystem detection functions would prevent breakage when APIs change (e.g., statfs syscall variations) and document expected behavior.
- [ ] Create filesystems_linux_test.go to mock /proc/filesystems and statfs syscalls
- [ ] Create filesystems_darwin_test.go to test macOS statfs behavior with different mount types
- [ ] Create filesystems_windows_test.go to test Windows volume enumeration
- [ ] Add tests for unsupported/unknown filesystem types to ensure graceful handling
Add GitHub Actions workflow for multi-platform testing (cross-compile validation)
The repo has build.yml, lint.yml, and goreleaser.yml workflows, but there's no explicit CI workflow that tests compilation and basic functionality on macOS, Windows, and BSD runners. This would catch platform-specific build issues early and validate that the platform abstraction layer works correctly.
- [ ] Create .github/workflows/test.yml that runs 'go test ./...' on ubuntu-latest, macos-latest, and windows-latest
- [ ] Add a basic smoke test step that runs 'duf' with '--version' and '--help' flags on each platform
- [ ] Configure the workflow to run on pull requests and merges to master
- [ ] Reference this workflow in the README.md build status badge (update the badge to point to test.yml instead of build.yml)
🌿Good first issues
- Add unit tests for mounts_darwin.go and mounts_windows.go: Follow the pattern in mounts_linux_test.go to add basic statfs parsing and edge-case tests for macOS and Windows mount stat retrieval. Catches platform-specific bugs early.
- Document the --only-fs vs --only-mp vs --only distinction clearly in README: README mentions filtering but the semantic difference (filesystem type vs mount point vs table category) could be clearer. Add concrete examples:
duf --only-fs tmpfsvsduf --only-mp /homevsduf --only local. - Add JSON output tests in main_test.go: The --json flag exists and is referenced in README but lacks automated tests validating output schema. Add integration tests that run duf --json and validate JSON structure (no unit test file exists yet for main.go).
⭐Top contributors
Click to expand
Top contributors
- @dependabot[bot] — 34 commits
- @actions-user — 32 commits
- @muesli — 23 commits
- @SuperSandro2000 — 1 commits
- @iascending — 1 commits
📝Recent commits
Click to expand
Recent commits
4636deb— build(deps): bump github.com/mattn/go-runewidth from 0.0.17 to 0.0.19 (dependabot[bot])0331c74— docs: update man page (actions-user)c636176— build(deps): bump github.com/mattn/go-runewidth from 0.0.16 to 0.0.17 (dependabot[bot])b9b8077— docs: update man page (actions-user)6ff827f— build(deps): bump github.com/muesli/mango-pflag from 0.1.0 to 0.2.0 (dependabot[bot])718089e— docs: update man page (actions-user)5106c2d— fix: create man page from pflag (muesli)2fda9bd— docs: update man page (actions-user)5c9aeee— feat: add noop -h flag for df compat (#325) (SuperSandro2000)b2f01a1— fix: parse modified git tree flag correctly (muesli)
🔒Security observations
The codebase shows a generally secure posture. As a CLI utility for disk usage reporting, it has minimal attack surface. No hardcoded secrets, injection vulnerabilities, or dangerous patterns were identified in the file structure. Dependencies appear to be well-maintained and commonly used libraries. Primary recommendations include maintaining regular dependency updates and monitoring Go security advisories. The project follows good practices with automated linting and building workflows configured in GitHub Actions.
- Low · Outdated Go Version —
go.mod. The project targets Go 1.23.0, which is relatively recent but may not receive security updates indefinitely. Go has a typical support window of 2 major versions. Fix: Regularly update Go to the latest stable version and monitor security advisories from the Go project. - Low · Transitive Dependency Management —
go.mod (indirect dependencies). The project relies on several transitive dependencies (indirect dependencies) which are included implicitly. While go.mod tracks them, their security posture depends on upstream maintainers. Fix: Regularly run 'go list -u -m all' and 'go mod tidy' to keep dependencies updated. Consider using 'go vulncheck' or similar tools to scan for known vulnerabilities.
LLM-derived; treat as a starting point, not a security audit.
👉Where to read next
- Open issues — current backlog
- Recent PRs — what's actively shipping
- Source on GitHub
Generated by RepoPilot. Verdict based on maintenance signals — see the live page for receipts. Re-run on a new commit to refresh.