Skip to content

CLI reference

Guilherme Selig edited this page Oct 21, 2026 · 1 revision

CLI reference

sdtally explains macOS System Data with measurements, no estimates. It is read-only and writes nothing to disk, not even a cache. Grant Full Disk Access to your terminal app before using it.

  • Text and JSON go to stdout. Errors go to stderr. A progress counter goes to stderr only when stderr is a terminal.
  • sdtally --help prints the built-in usage; sdtally --version prints the version.
  • Where to find it: inside the app at SDTally.app/Contents/Helpers/sdtally, or at target/release/sdtally after cargo build --release.

Synopsis

sudo sdtally [--top N] [--json] [--binary] [--lang pt|en] [--color auto|always|never]
sdtally <path> [--top N] [--depth N] [--json]
sdtally why <path> [--json]
sdtally --quick --json [--since EPOCH_SECONDS] [--parts LIST] [--redact names|off]
sdtally --quick --json --watch
sdtally --auto
sdtally --last --json [--redact names|off]
sdtally --history --json [--redact names|off]
sdtally --mcp [--redact off]
sdtally --redact names --stdin
sdtally --catalog --json
sdtally --verify [--json]

Modes

Full breakdown: sdtally

The Data volume account: the Settings screen reproduced, what takes the most space, what was partial or not measured, the unexplained remainder, informational blocks (purgeable, repeated clones and hard links, cloud-only files, APFS metadata, Trash by age) and "Why space may not come back".

  • Run with sudo for the complete breakdown. Without root it still runs, marked INCOMPLETE (no sudo) with the list of what is missing.
  • With sudo, the home folder measured is the one of SUDO_USER.
  • Ctrl-C stops the scan and prints the partial report marked INCOMPLETE (interrupted); exit code 130.
  • --json prints the whole report as JSON, including the full ranking, advice ("What to Do") and not_freed. See JSON output.

Branch: sdtally <path>

The children of a folder by unique allocated size, with freed if deleted (the private bytes: what deleting it would actually give back, excluding blocks shared with clones). The path must be a folder on the Data volume; other volumes are refused.

sdtally ~/Library --top 10
sdtally ~/Library --depth 2
sdtally ~/Library/Caches --json

Root is not needed. Protected folders show as protected, without private bytes.

Item: sdtally why <path>

Raw attributes of one file or folder: logical and allocated size, private size, file ID, clone ID, flags, link count, xattr count and size, and for folders whether it is a graft root and its APFS directory statistics.

sdtally why ~/.colima
sdtally why ~/Library/Caches --json

Quick reading: sdtally --quick --json

Only what changes all the time, without scanning the disk: the Settings screen, used, free (capacity), purgeable by service, APFS containers and swap. Requires --json. No root.

Option Meaning
--since EPOCH_SECONDS The start time of the previous reading. Reads the Settings log only from there on, and only while the Storage pane is open. With the pane closed the log is not read and settings_screen.screen is not_measured
--parts LIST Comma-separated subset of meta, volumes, swap, uso, purgeable, tela. Keys of other parts are left out of the JSON. An unknown name or an empty list is an error
--watch Follows the Settings log (log stream) and writes one compact JSON line per new Storage screen, until stdin closes. Not combinable with --since or --parts

Live tree: sdtally --auto

One full pass, then only the folders FSEvents reports. Writes one compact JSON line per change of 10 MB or more (and periodically for smaller changes), until stdin closes. As root (the app's helper runs it this way when "Automatic with root" is on) it also opens protected folders. Takes no other options. See Automatic vs Full measurement.

Saved measurements: --last and --history

They read what the app saved in ~/Library/Application Support/SDTally/Medicoes/. They never measure.

  • sdtally --last --json: the newest full measurement, re-serialized.
  • sdtally --history --json: a summary of every saved measurement, oldest first (generated_at, tool, root, full_disk_access, complete, used, unexplained, percent_of_used).

Both require --json and refuse to run as root. Symlinks, files over 20 MB and files with an unexpected schema are skipped with a warning on stderr.

MCP server: sdtally --mcp

An MCP server over stdio (JSON-RPC 2.0, one message per line) with three tools and no arguments: quick, last_measurement, history. Redacts personal names by default; --redact off disables that. Refuses root. See JSON output.

claude mcp add sdtally -- sdtally --mcp

Redact a file: sdtally --redact names --stdin

Reads a measurement JSON from stdin (up to 20 MB) and prints it with the user name and personal folder names replaced. This is what the app uses for exports with "Replace Personal Names" on.

sdtally --redact names --stdin < measurement.json > shareable.json

Catalog: sdtally --catalog --json

All explanation cards (what an item is, whose it is, what is lost, whether macOS cleans it on its own, the next step, references, the macOS version it was checked on) and, for every data source, how it was checked against Apple's numbers. Requires --json.

Verify: sdtally --verify [--json]

Checks, now and side by side, the numbers that an Apple command shows the same way: Data volume used against df -k, swap against sysctl vm.swapusage, Time Machine snapshots against tmutil listlocalsnapshots /. Each check runs Apple's command, then sdtally's reading, then Apple's command again; the result is equal, within (the disk changed between readings) or outside. Sources that cannot be checked this way are listed as not_checkable with the reason. Refuses root.

Exit code: 0 if nothing is outside, 1 if something is outside, 2 on a usage error.

Options

Option Applies to Meaning Default
--top N text output Ranking lines shown (JSON always has the full ranking) 15
--depth N <path> Levels below the path 1
--json most modes JSON on stdout off
--quick Quick mode; requires --json and no path off
--since EPOCH_SECONDS --quick Incremental Settings log reading off
--parts LIST --quick Only these parts all
--watch --quick --json Follow the Settings log off
--binary text output GiB (2^30) instead of GB (10^9) GB, as in System Settings
--lang pt|en text output, messages Language pt if the first non-empty of LC_ALL, LC_MESSAGES, LANG starts with pt, otherwise en
--color auto|always|never text output Color auto: only on a terminal and without NO_COLOR
--redact names|off measurement JSON (--json, --quick, --last, --history, --mcp, --stdin) Replace the user name and personal folder names on only with --mcp
-V, --version Print the version and exit
-h, --help Print help and exit

Numbers given to --top and --depth must be greater than 0.

Rules for combining options

  • --quick only with --json and no path.
  • --since and --parts only with --quick.
  • --watch only with --quick --json, without --since or --parts.
  • --last and --history require --json; --mcp goes without --json. None of them takes a path, --quick or another of them.
  • --catalog requires --json and takes no path or other mode.
  • --stdin requires --redact names and takes no path or other mode.
  • --verify takes no path, --quick or other mode.
  • --auto takes no other options.
  • --redact only where a measurement JSON is printed.

Breaking a rule prints a message and exits with code 2.

Exit codes

Code Meaning
0 Success
1 --verify found a value outside Apple's; or the safety policies could not be set (nothing was read)
2 Usage error, refused path, or a mode that failed (for example no saved measurement for --last)
130 Interrupted with Ctrl-C (a partial report was printed)

Environment

Variable Effect
LC_ALL, LC_MESSAGES, LANG Default language
NO_COLOR Disables color in auto mode
SUDO_USER With sudo, whose home folder is measured
SDC_PANIC=1 Development and CI: print panic messages on stderr instead of recording them as stage errors

Notes

  • The System Data line comes from the Storage pane's log, which keeps the value for less than about 21 hours. Open System Settings > General > Storage, wait for it to load, and run again if it says there is no record.
  • Units: GB means 10^9 bytes, like System Settings. Use --binary for GiB.
  • Safety: before reading anything, sdtally disables, for its own process, materializing dataless files and updating access times. If that fails, it exits without reading.

Clone this wiki locally