spacetrace
EN
Download

What changed

Every release, newest first. The same text ships inside the apps, so what you read here is what the app tells you after it updates.

development milestoneVersions marked as development milestones were never tagged and have no downloadable files. They are listed because the work happened, not because you can install them.

Desktop app

0.9.0

Downloads and checksums

Added

  • The map can now be drawn as cushions, the look SequoiaView and WinDirStat made familiar: every rectangle is lit as a bump and every folder as a larger bump under what it holds, so what belongs together reads as one shape without tracing lines. The colours mean what they did, kind or age; only the light varies across a tile. Choose Flat or Cushion beside Map and Rings. The choice is remembered, and the map stays flat until you pick it.

Changed

  • On Linux, scans of btrfs and XFS now count blocks shared between files once, the way the disk holds them: reflinked copies (cp --reflink, the coreutils 9 default) and btrfs snapshots are no longer charged once per name. Three reflinked copies of a 100 MB file used to show 300 MB on disk and now show 100 MB, which is what df says. Totals on those filesystems therefore drop, and a comparison with a snapshot taken by an earlier version shows a decrease that never happened on disk. Compressed btrfs files keep their uncompressed size, because measuring what they hold needs root.

Performance

  • Scans on macOS are 15-33% faster and hold a third less memory. Copy-on-write clones used to be found in a step of their own after the walk, opening every candidate file one at a time - the "clone candidates checked" count at the end of a scan. APFS names the clone family inside the directory listing the walk already reads, so that step is gone. Measured: 415,503 entries 485 to 412 ms, 1,064,452 entries 2133 to 1431 ms, peak memory on the larger 299 to 200 MiB. Clones smaller than 64 KiB are now counted once too, so a folder of many small clones shows a little less on disk, closer to what the disk really holds. Scans use 6 threads rather than 8, which re-measured faster once the walk got cheaper.
  • Saving a scan to the history takes about 17% less time: its checksum is computed while the rows are written, not in a second pass.
  • Scans on Linux are 6 to 14% faster: folders are read in large batches and each entry is asked relative to its folder. On XFS with reflinked files, more threads no longer make a scan slower: 100,000 such files took 200 ms instead of 855 ms.
  • On Linux, spinning disks are detected and scanned with one thread, each folder's entries in the order they lie on the disk: a cold scan of a simulated spinning disk took 0.9 s instead of 11.5 s.
  • On Windows, when the app runs as administrator, a scan of a whole NTFS volume reads the volume's master file table instead of opening every file, with the same answer. Every other scan walks as before.

Fixed

  • On macOS the space of an APFS clone family is now charged to the same file on every scan: the shallowest one, and on a tie the one with the first path. It used to go to whichever copy a scan thread reached first; the total was right, but with clones in different folders the bytes moved between them from one scan to the next with nothing on disk changing, so comparing two snapshots of an unchanged disk showed one folder growing and another shrinking. A comparison with an older snapshot may show such a move one last time.
  • Colouring the map by Age showed no ages for a snapshot opened from the database or from an agent, and its age profile read 0 B in every band; only a fresh scan had them. A snapshot now colours and profiles the same as the scan it was saved from.
  • On the map, a folder's label and its first subfolder's were drawn on top of each other: both went in the same corner, one pixel apart, so a dist/ holding a large cache/ read "dist/ache/". A label that would cover another now moves down below it, inside its own tile, and is left out when there is no room there; no two labels overlap any more.

0.8.0

Downloads and checksums

Added

  • A running scan is now shown as it fills in: the same folder list, map and inspector a finished scan gets, over a tree that grows every second. Until now the screen held nothing but a percentage until the scan ended. Every figure in it is what has been read so far, so the view is marked partial and neither deleting nor saving is allowed while it runs; what you have opened, selected or zoomed into survives the refreshes and the moment the scan lands.
  • Scans now open in tabs. Home stays on the left and is never closed, so starting another scan no longer means losing the one you are reading; each scan gets a tab of its own and they can be switched between freely. Closing a tab gives its memory back — a scan of a million entries is about a hundred megabytes for as long as it is open.
  • The opening screen lists the disks. Scanning a whole filesystem was always possible and had no button anywhere: you had to know that the folder chooser accepts the root of a drive. Each disk is shown with its free space, external drives included.

Changed

  • The top bar carried fourteen buttons and wrapped onto three lines at the width the window actually opens at, pushing the map down. Every control now sits beside the thing it changes: the bar holds the app and where a tree comes from, the actions for the open scan are behind the ⋯ next to its path, and the map's shape and colouring are on the map. Which measure the figures are in is chosen by clicking the total you want — both are printed either way, the chosen one bright and underlined. "Reset zoom" is gone; the first step of the path above the map already did it.
  • The folder list starts narrower. More than half its width went to the figures column; that column was tightened by 16px — gaps and the length of the bar, no figure says less than it did — and the starting width came down with it. A width you set yourself is still remembered, and double-clicking the divider resets it.
  • The window can no longer be made too small to work in. The smallest size is now 1080 by 700 rather than 900 by 600: at the old one the map ended up smaller than the folder list beside it.
  • Rescan, Save snapshot and History are no longer hidden behind a single unlabelled button. They are named buttons on the line that says what is open, they are at the foot of the right-click menu, and History — the only one that does not need a scan open first — is on the opening screen too.

Fixed

  • The preview a first scan drew stayed blank for the whole scan: its drawing area could not take a height, so it never asked for anything and nothing but the heading "Reading the top level" was left on screen.
  • The map painted over the details column on the right as soon as the folder list was dragged wide enough — or the window made narrow enough — that the map was left with less room than its own key is wide. The two side panes now give way, the map keeps a minimum width, and none of the three overlaps another.
  • The map collapsed as soon as an error was reported above it: the error strip took the space that belonged to the map. It disappeared at exactly the moment the window was trying to explain what had gone wrong.
  • The map got substantially faster without losing any detail. Moving the pointer across it made the whole window stutter: every move repainted all ~112,000 rectangles in order to shift one thin outline — 39.4 ms per move, now 0.13 ms. The picture itself is drawn as a few dozen paths rather than one call per tile (40.6 ms down to 21.4 ms), and the coordinates cross the boundary in shorter form, taking a map's response from 10.4 MB to 5.2 MB.
  • The Website and Source code links in the About panel, and the changelog link in the update notice, did nothing. The permission that lets this app hand an address to the browser allows no address unless it is given a list, and it had none; the failure was then discarded at every call site, so a button that was never going to work looked exactly like one that was.
  • Right-clicking anywhere the app had no menu of its own brought up the web view's, offering Reload — which threw away every open scan and looked like a crash rather than something anyone asked for. That menu is now suppressed everywhere except in text fields, where it is the only route to copy and paste.
  • A directory tree nested past about 210 levels no longer closes the app. The walk recurses once per level and its threads had the ordinary default stack, so a deep enough tree overflowed it — and because a scan runs inside the app itself, the whole window went with it, leaving no message behind. The walk threads now get a 16 MiB stack and stop at 1024 levels: the directory is listed among the items that could not be read, and the scan carries on.

0.7.0

Downloads and checksums

Added

  • A first scan now shows what it is finding while it runs, instead of a blank panel and a counter. The top-level folders appear as a map and grow as their contents are read, so the big one usually announces itself long before the scan ends. The figures are what has been found so far and the view says so — a folder that has stopped growing looks exactly like one that is finished. The same layout routine draws this and the finished map, so nothing rearranges when the scan lands. A rescan leaves the map you are already reading alone, as before.
  • The same folder can now be drawn as rings instead of rectangles. One ring per level, and an entry's angle is its share of the folder it sits in — so how deep something goes, and what is nested inside what, is the picture rather than something to work out from nesting. The treemap stays the default and this is a second opinion, for a reason worth knowing: an arc further from the middle covers more of the screen for the same size, so compare angles and not areas. Clicking selects, double-clicking a folder goes into it, and the colour switch works here too.

0.6.2

Downloads and checksums

Fixed

  • The age heat map's key named every band "undefined" instead of "Under a week", "1–3 months" and so on. The colours and the byte figures beside them were right; only the words were missing, which made the one part of the view that explains the colours unreadable.

0.6.1

Downloads and checksums

Added

  • The map can be coloured by age instead of by kind. Blue is this week, red is over two years, and a folder takes the age of its middle byte — so half of what is inside it is older than its colour says. The key beside it gives the bytes in each band for the folder on screen, which turns "red is old" into "48 GB here has not been touched in two years". A folder's own date is deliberately ignored: it moves when anything is added beside it and says nothing about what is inside.

Fixed

  • Snapshots brought in with spacetrace import open in the app. They were stored with a malformed root, so the app refused them as an unusable tree.

0.6.0

Downloads and checksums

Added

  • When a scan stops making progress, the progress strip now says so and names the folder it is waiting on, instead of animating a bar over a scan that is going nowhere. A network share that has stopped answering blocks in the kernel and no app can lift that — but knowing what it is waiting on is what lets you decide whether to wait or stop.
  • A folder's whole history on one line. History shows every stored snapshot of a folder as a chart, with what changed between each pair beside it; clicking a step opens the comparison for exactly that jump. The axis starts at zero, so the height of the line is the size itself.

Performance

  • Scans use at most eight threads instead of one per core, which made them faster on every directory tree measured — 39% on a small one, 11% on a large one. A walk is syscall-bound: past a point the threads queue in the kernel rather than work.
  • Scans on macOS are about 2.3 times faster, following the same change in the scanning core: the system can report a folder's names and its files' sizes in one request instead of one request per file.

Fixed

  • The progress strip appeared to freeze at the end of every scan: after the walk there is a second pass looking for copy-on-write clones, and no counter moved during it. That phase now says “Finishing up” and counts what it checks, instead of showing a file count that has stopped.

0.5.0

Downloads and checksums

Added

  • Snapshots now carry a checksum of their content. One pulled from an agent that changed on the way is refused rather than drawn: a flipped bit leaves a perfectly valid tree, and a treemap renders a wrong number every bit as convincingly as a right one.

Changed

  • The snapshot database this app shares with the command-line tool moves to a new schema. This version reads the old one without ceremony; the reverse does not hold, so update both together if you use both.

0.4.2

Downloads and checksums

Fixed

  • The .dmg would no longer open on macOS. The signing identity added in 0.4.1 was applied to the disk image as well, and an image signed by a certificate macOS does not trust is refused at mount time — so the warning arrived when you opened the download, before the app ever ran. The image is unsigned again; the app inside keeps its identity.

0.4.1

Downloads and checksums

Fixed

  • macOS forgot every permission you had granted whenever the app updated: without a stable signing identity the system treats each release as a different app, so Full Disk Access read as on while being ignored, and every scan asked again folder by folder. The app now carries one identity across releases, so a permission granted once stays granted.

0.4.0

Downloads and checksums

Added

  • Temporary install scripts for macOS and Windows that fetch the bundle with curl or Invoke-WebRequest, verify it against SHA256SUMS and install it. A download made that way carries none of the marks a browser writes, so Gatekeeper and SmartScreen never fire. They go away once the app is signed.
  • Without Full Disk Access, macOS asks about each protected folder separately — mid-scan, in an order nobody can predict. The welcome screen now says so before the first scan and has a button straight to the right settings pane. The system's own dialog finally explains why a disk analyser wants to read your files, too.

Changed

  • The What's new panel now lists released versions only. Entries that had landed but were in no release described work your copy does not contain.

Fixed

  • The macOS install instructions described the right-click Open trick, which Apple removed in macOS 15. They now give the System Settings → Privacy & Security → Open Anyway route instead.

0.3.1

Downloads and checksums

Fixed

  • The update check works. 0.3.0 announced it, but no update manifest was published alongside it, so the app had nothing to check against.

0.3.0

Downloads and checksums

Added

  • Error messages are in your language too. What the operating system says — Permission denied and the like — stays in its own words, because those are the words that help when you search for them.
  • The app checks for a newer release when it starts and offers to install it. Nothing is downloaded until you ask for it. On macOS the app is still unsigned, so the system may ask you to confirm it again after an update.
  • The app speaks five languages: English, Turkish, Italian, French and German. It follows your system's language on first launch, and the choice can be changed at any time.
  • A panel showing which version and which build you are running, plus what changed in recent releases. It works offline: the changelog is compiled into the app itself.

Performance

  • Opening a large scan uses less memory, following the smaller tree representation in the scanning core.

0.2.0

· development milestone

Added

  • Installable packages for macOS, Windows and Linux, built on every push.
  • A switch for which measure the map and the lists follow: what files claim, or what the disk holds.

Changed

  • The window never blocks. Long work runs off the main thread and reports progress, and a scan can be cancelled while it runs.

0.1.0

· development milestone

Added

  • The first desktop app: a treemap of a folder, a tree beside it, and the details of whatever is selected on the right.
  • Open a fresh scan, a stored snapshot, or a snapshot read straight off an agent running on a server or NAS.
  • Move entries to the Trash from inside the app, behind a confirmation that names exactly what leaves.

All releases · Download

Command line

0.10.0

Downloads and checksums

Added

  • spacetrace scan --ssh host /path scans a machine you can reach over ssh, with nothing installed there, and keeps the snapshot in the local database, where scans, diff, ls --scan and verify treat it like any other. A copy of this same version is uploaded into a private temporary directory on the other side (this binary when it runs there, otherwise the published release for that platform, checked against SHA256SUMS and cached), scans, sends its database back and is removed: also on failure, on Ctrl-C, and when spacetrace is killed outright, because the remote side cleans up as soon as the session ends. One connection, so at most one password prompt. The snapshot carries the remote machine's hostname and path, so it joins that machine's history. The cost is ssh access, an upload of about 7 MB per run, and room in /tmp or $HOME for the snapshot. Not available on Windows yet.
  • spacetrace scan s3://bucket/prefix scans an S3 bucket - AWS, or MinIO, Cloudflare R2, Backblaze B2 and Wasabi through --endpoint - and --save stores it as an ordinary snapshot that ls --scan, diff --path s3://..., age --scan and export read unchanged. Credentials and region come from the same places the aws CLI reads, in its order: keys, an assumed role, a web identity token, IAM Identity Center after aws sso login, credential_process, ECS/EKS container credentials and EC2 instance metadata. Temporary keys are renewed before they expire; a role that needs an MFA code is not prompted for, so export its keys first with aws configure export-credentials. --no-sign-request lists a public bucket. An AWS bucket is listed 16 requests at a time, split by folder (587,000 keys in 30 s instead of 175 s, measured against us-west-2); any other --endpoint stays one stream unless --threads asks for more, because MinIO measured slower in parallel. Keys are drawn as folders split on /. The total counts current versions only: old versions, delete markers and unfinished multipart uploads are billed but not listed, and the output says so. Keys with a . or .. path segment are not drawn: they count as unreadable entries and the output names them. diff --path s3://... compares snapshots of one service only, so a MinIO and an AWS bucket of the same name are never paired.
  • New spacetrace watch <folder> shows live which folders are growing or shrinking since it started, how fast, biggest first - the same rows diff would report. It scans once, then follows filesystem events (FSEvents, inotify, ReadDirectoryChangesW) and lists only the folders they name again with the scanner, so hardlinks, symlinks, --exclude, -x and --depth mean what they mean for scan. It refreshes in place on a terminal, appends lines into a pipe, and prints one JSON object per refresh with --json; --interval sets the pace. A hardlinked file is followed by its device and inode and counted once, so a build tree full of hardlinks needs no full rescan; only events the system reports as dropped, or a link whose other names cannot be found, trigger one, and the output says so; clones are counted at their full size. On Linux, running out of inotify watches stops it with the sysctl that raises the limit.
  • spacetrace pkgs says which installed package the bytes under a folder belong to, and how much belongs to none - usually the part somebody put there by hand. Given one file instead, it names the package that owns it. It reads dpkg, pacman, apk and Homebrew straight off the disk and asks rpm where an rpm database exists; a database it cannot read is named in the output rather than its files quietly counted as unowned. On merged-/usr systems a list that says /bin/ls is matched to /usr/bin/ls, where the file is: matching as written would have called 17% of a Debian 12 /usr unowned. On macOS it also reads the installer receipts, so everything a .pkg installed - Apple's own packages, the Command Line Tools, Office, Node.js - is credited to its package with the same file list pkgutil --files gives, read straight off the disk in a fraction of a second instead of seconds. A scan of /System/Volumes/Data/Applications gives the same answer as one of /Applications, and a file an updater renamed with different capitals still counts for its package. A damaged receipt is named in the output and the rest are still read. Files a package's install script generates, such as Python bytecode or font caches, are in no list and show up as unowned. It works on this machine only, so a snapshot from another host is refused.
  • The agent now serves Prometheus metrics at /metrics, behind the same bearer token as the rest of its API. Per configured root: when the newest snapshot started and how long it took, its logical and on-disk size, files, directories, unreadable paths, the free and total space it recorded, whether a scan is running, and how many snapshots are stored; plus the build and the start time. A root never scanned still appears, with zero snapshots, so "never scanned" can be alerted on. A scrape reads only what is already stored - it starts no scan and does not touch the scanned disks - and took 2.2 ms against a store of 20,005 snapshots. docs/AGENT.md has the scrape configuration.
  • On macOS, spacetrace scan --save and the agent's scheduled scans start from the last snapshot and reread only the folders FSEvents says changed: /Applications in 239 ms instead of 406 ms. The result is the same as a full scan or it is a full scan: any doubt (no cursor, another volume, a slow or lost journal, too many changes, a base older than two days, other options, a damaged or imported base) means a full scan, and the snapshot records why. --full and per-root incremental = false force a full scan. A root on another volume than your temporary folder, such as an external disk, is always scanned in full: there FSEvents cannot be relied on to have numbered a change made just before the scan.
  • scan --json reports rescan (full, incremental or fallback:<reason>) and an incremental object (replay and base-load time, folders reread, entries reused).
  • spacetrace scan --disk auto|ssd|hdd paces the walk for the disk underneath. hdd walks with one thread and, on Linux, asks for each folder's entries in the order they lie on the disk; auto, the default, detects spinning disks on Linux and walks everything else as before. On a simulated spinning disk a cold scan took 0.9 s instead of 11.5 s. --json reports the pace (disk, threads, disk_decided). The agent takes the same setting per root as disk.

Changed

  • On btrfs and XFS the on-disk total now counts blocks shared between files once, the way the disk holds them: reflinked copies (cp --reflink, the coreutils 9 default) and btrfs snapshots are no longer charged once per name. Run as root on btrfs, compressed files count at their compressed size. Measured: three reflinked copies of a 100 MB file used to report 300 MB and now report 100 MB, which is what df says; a 100 MB compressed log reports 3 MB instead of 100 MB. Totals on those filesystems therefore drop, and a diff against a snapshot taken by an earlier version shows a decrease that never happened on disk. Without root, compressed files stay at their uncompressed size and the summary says so. On ZFS it says that block clones and deduplicated blocks cannot be seen by a scan. To do this each file on btrfs and XFS is opened once, which costs 0.4 to 0.9 ms per 1,000 files with a warm cache, more on XFS when most blocks are shared. --no-clone-dedupe switches it off and gives back du's number.

Performance

  • Saving a snapshot takes about 17% less time: the content hash is computed while the rows are written, not in a second pass. The agent's /status no longer reports a checksumming phase.
  • Scans on Linux are faster: directories are read in large batches and each entry is asked relative to its directory, without per-entry allocations. The static build the agent ships as gains the most — 1.3 to 3.4 times faster on the trees measured — and glibc builds 6 to 14%.
  • On XFS filesystems holding reflinked files, scans with several threads are no longer slower than with one: the filesystem is asked about shared blocks one thread at a time, in runs. A tree of 100,000 reflinked files took 200 ms instead of 855 ms warm, and 248 ms instead of 971 ms cold. XFS without reflinked files, btrfs and ext4 are unchanged.
  • On Windows, a scan of a whole NTFS volume run as administrator reads the volume's master file table in one sequential pass instead of opening every file. The answer is the same entry for entry, which CI checks on a real volume. Anything else — a folder below the volume's root, no elevation, ReFS, FAT, a network drive — walks as before. --no-mft always walks.

Fixed

  • spacetrace update no longer fails on a slow connection. The archive download ran under the same five-second limit as the version check, and that limit covers the whole body, so a 12 MB archive needed 2.4 MB/s or it timed out. Downloads now have five minutes.
  • spacetrace age --scan ID reported 0 B in every age band for every stored snapshot; only a fresh scan showed real sizes. It now gives the same answer for a snapshot as for the scan it was saved from.
  • A pushed or pulled snapshot is checked in full before it is stored: its tree must be sound and every value of the right type. A snapshot with a correct checksum and a broken tree used to be stored anyway, after which every command reading that database failed on it; now it is refused and nothing of it is kept. A snapshot dated more than a day in the future is refused too: it would have stayed the newest of its folder for good. The check does not hold up the agent's own scans, and a snapshot claiming an absurd number of files no longer crashes spacetrace when opened or makes the next scan of that folder abort.
  • A command whose output is closed early (spacetrace scans | head -1) now ends quietly with exit code 0 instead of panicking with "failed printing to stdout: Broken pipe". 0 and not 141, because a reader that stops has what it wanted, and a script under set -o pipefail would otherwise fail where nothing went wrong.
  • On macOS the space of an APFS clone family is now charged to the same member on every scan: the shallowest one, and on a tie the one with the first path. It used to go to whichever member a scan thread reached first; the total was right, but with clones in different folders the bytes moved between them from one scan to the next with nothing on disk changing, and a diff of two snapshots of an unchanged disk showed one folder growing and another shrinking. A diff against an older snapshot may show such a move one last time. Scan time is unchanged.

0.9.1

Downloads and checksums

Changed

  • Clones smaller than 64 KiB are deduplicated too, and the default thread count dropped from 8 to 6. The size floor existed because each clone check cost an open file; it costs nothing now, so a tree of many small clones reports less than it did - closer to what df says the disk holds. clones_deduped rises accordingly. The thread default was re-measured after the walk got cheaper: 6 is at or near the best on all three test corpora, where 8 now costs 22% on the largest of them. Use --threads to override.

Performance

  • macOS scans are 15-33% faster and hold a third less memory. Copy-on-write clones used to be found in a phase of their own after the walk, opening every candidate file one at a time; APFS reports the clone family inside the directory listing the walk was already reading, so that phase is gone. Measured against the previous build, warm cache, interleaved runs: 50,189 entries 94 to 78 ms, 415,503 entries 485 to 412 ms, 1,064,452 entries 2133 to 1431 ms. Peak memory on the largest of those fell from 299 to 200 MiB, because the walk no longer builds a full path for every entry it lists - only for the directories it descends into. Clone deduplication is now free rather than 15-31% of the scan, so --no-clone-dedupe no longer buys any speed.

Fixed

  • ca_file in remotes.toml now works on Windows, and now trusts only the certificate it names. Connecting to an agent serving its own TLS failed there with InvalidCertificate(UnknownIssuer) however correct the certificate was: the client added it to the platform's own roots, and the Windows verifier only reconsiders an added root when the chain came back incomplete - a self-signed certificate's chain is complete and untrusted, so the added root was never looked at, and self-signed is the only kind ca_file is for. The client now trusts exactly the certificates in ca_file and no public authority, which is what the documentation already described as pinning and what the other platforms should have been doing too.

0.9.0

Downloads and checksums

Added

  • The agent can now serve its API over HTTPS itself: tls_cert_file and tls_key_file under [server] in the configuration, both or neither. Until now that needed a reverse proxy in front, which on a NAS with no domain name of its own meant putting the token and the file inventory on the network in plaintext. A self-signed certificate is enough; the client is told which one to trust with ca_file in remotes.toml. Where a domain name exists a reverse proxy is still the better answer, because it renews certificates and the agent does not: a renewed certificate takes a restart. The certificate needs the address clients use as a subject alternative name.

0.8.0

Downloads and checksums

Added

  • The agent now limits how many requests one client address may make, answering 429 with a Retry-After above the limit. It counts before checking the bearer token, because the two things a token cannot bound are exactly the ones that need it: /health needs no token by design, and a wrong token still costs a reply. The default of 120 a minute is far above ordinary use; what it stops is a client stuck in a retry loop spending the disk the agent exists to measure. Behind a reverse proxy every request arrives from the proxy, so the limit becomes one shared allowance — set rate_limit_per_minute = 0 and limit in the proxy where that matters.

Changed

  • The CSV export now lists each folder immediately followed by what is inside it. It used to write a whole set of siblings together and their contents further down, which put a folder and its files pages apart in the spreadsheet. The columns and the rows themselves are unchanged.
  • spacetrace scan --save now says what it is doing while it writes the snapshot to the database. That write is not a quick tail on the end of a scan — on a folder of 412,983 entries the walk takes 0.8 seconds and the write another 0.6, and at ten million entries it is about fourteen seconds — and until now the progress line was cleared the moment the walk ended, leaving the command apparently frozen. The agent reports the same two stages on /status.

Fixed

  • spacetrace dupes listed the same duplicates in a different order every time it ran, so comparing two reports showed differences that were not there. The order now follows the paths, which do not change between runs.
  • A directory tree nested past about 210 levels no longer aborts the scan. The walk recurses once per level and its threads had the ordinary default stack, so a deep enough tree overflowed it and the process died outright — in the agent that took the HTTP API and the scheduler with it, and no snapshot was written. The walk threads now get a 16 MiB stack and stop at 1024 levels, recording the directory as unreadable and carrying on; a tree deeper than the operating system can name is reported the same way, with its path and its reason.

0.7.0

Downloads and checksums

Added

  • spacetrace dupes finds files holding identical contents and says what deleting the extras would give back. It reads as little as it can: files of different lengths cannot match and the scan already knows every length, files that share a length are separated by their first 16 KiB, and only what survives both is read in full. On a 33.8 GiB tree of 375,585 files that came to 2.6 GiB of reading — 7.7% — and a second run read 30 MiB, because whole-file hashes are remembered between runs. Hardlinked names are listed separately and counted as reclaiming nothing, since they already share their bytes. Nothing is deleted; which copy to keep is not a decision this tool has the context to make.

Performance

  • Scanning uses markedly less memory. The walk used to build a tree of its own and copy it into the final one, so both were in memory at the peak; it now writes entries into the final tree as each directory is read. On a 412,983-entry folder the peak fell from 91.5 MB to 57.6 MB, and to 49.3 MB when a previous scan of the same folder is on record to size the structure from. Scanning takes the same time as before, and every figure it reports is unchanged.

0.6.1

Downloads and checksums

Fixed

  • A snapshot created by spacetrace import could be stored and then never opened again: every attempt failed with "entry 0 is not a root: it claims a parent". The import wrote a malformed root and nothing noticed until the read. Snapshots already imported are readable by this version without being imported again.

0.6.0

Downloads and checksums

Added

  • --threads N chooses how wide a scan runs, and the agent takes the same setting per root. There is no best number: the optimum moves with the size of the tree, and someone who knows their disk will choose better than any built-in default.
  • When a scan stops making progress, the progress line now says so and names the directory it is waiting on, instead of going on claiming to be scanning. A network share that has stopped answering blocks in the kernel and no timeout in this program can lift that — but knowing what it is waiting on is what lets you decide whether to wait or quit.
  • spacetrace import reads an ncdu or gdu JSON export and stores it as a snapshot, so scans you already have become something to compare against — including scans of a machine that no longer exists to be rescanned. A directory's own apparent size is dropped on the way in: counting it is what makes du --apparent-size disagree with the figure this tool reports.
  • spacetrace export --format csv writes one row per entry for a spreadsheet, with --depth to stop at the top few levels of a tree no spreadsheet would open whole. Both measures are columns rather than a setting — what files claim and what the disk holds — alongside each entry's own cost, so a total can be rebuilt without counting a file once for every folder above it. Commas, quotes and newlines in names are quoted properly; they are legal in a filename and a naive export turns them into silently wrong rows.
  • spacetrace age answers the other question a full disk raises: not what is big, but what nobody has touched. Bytes are grouped by when they were last modified — the bands are yours to set with --bands — and weighted by size rather than by file count, because a hundred thousand stale source files are not the answer and one stale disk image is. Files whose modification time was never recorded are reported separately instead of being counted as fifty years old.

Changed

  • The agent's /status now says whether a running scan is working or wedged. scanning carries one object per scan instead of a bare path: live counters, the phase (walking or finishing — after the walk only the clone probe moves, so counting files alone reads a healthy scan as a stuck one), and, once every counter has stood still, how long for and which directories it is waiting on. The stall is timed by a watcher inside the agent, so polling /status rarely does not inflate it.

Performance

  • Scans now use at most eight threads instead of one per core, which was faster on every directory tree measured — 39% on a small one, 11% on a large one. A walk is syscall-bound: past a point the threads queue in the kernel rather than work. --threads N overrides it.
  • Scans on macOS are about 2.3 times faster. The old walk asked the kernel for a directory's names and then asked again, once per entry, for each entry's size and dates; macOS can answer both in a single call, and now does. Measured end to end on two real trees: 1293 ms to 556 ms on one, 1554 ms to 646 ms on the other, with both versions reporting byte-for-byte the same totals.

Fixed

  • The progress display appeared to freeze near the end of every scan. After the walk there is a second pass looking for copy-on-write clones, and it moved no counter at all — on ~/github that was 1193 of 1989 milliseconds. That phase now says what it is and counts what it checks.
  • A network share whose server has gone away no longer wedges the whole scan. The first lookup into a mounted filesystem cannot be interrupted once it hangs, and because a directory is listed on one thread, one dead share used to take every one of its siblings with it. Scans now read the mount table first, approach a mount point through a thread they are willing to abandon, and after 60 seconds record it as an unreadable path and carry on — so the result is short by that one filesystem and says so, instead of never arriving. --mount-timeout 0 restores the old behaviour; measured cost of the check is about a millisecond on a 300,000-entry tree.

0.5.0

Downloads and checksums

Added

  • Snapshots now carry a checksum of their content, and spacetrace verify checks it. A snapshot that changed on the way here is refused on import rather than believed: a flipped bit leaves a perfectly valid tree that reports a wrong number, which is precisely the failure nothing could see before.

Changed

  • The snapshot database moves to a new schema so the checksum has somewhere to live. Older builds will no longer open a database this one has written — they say so plainly rather than misreading it. If you use the desktop app on the same history, update it too.

0.4.1

Downloads and checksums

Fixed

  • install.sh and spacetrace update find the right release again. All three components publish into one repository, so GitHub's idea of the latest release briefly meant the hub's — which install.sh could not install, and which the update check read as no version at all.

0.4.0

Downloads and checksums

Added

  • The agent reports on /status when a newer release exists. A notice only: it never installs anything itself. Once a day, sending nothing about the machine, and update_check = false turns it off entirely.
  • spacetrace update installs the newest release over the running one, after verifying the download against the published SHA256SUMS.
  • A once-a-day check for a newer release, printed as one line on stderr. It runs only on a tagged build in a terminal, explains itself the first time, and stops entirely with SPACETRACE_NO_UPDATE_CHECK=1.
  • --version now says which build it is: the commit, the date it was built and the channel. The agent reports the same on /health and /status.
  • Every release now comes with written release notes in five languages, and the repository has a CHANGELOG.md.

Changed

  • The promise that on-disk sizes agree with du where no blocks are shared is now enforced by a test that runs real du, rather than being a claim in the documentation.

Performance

  • Scanning a large tree uses noticeably less memory: a tree node shrank from 104 to 72 bytes and names moved into one shared arena.

Fixed

  • install.sh verifies the download against the published SHA256SUMS. The file was published with every release and never read.
  • APFS clones are counted once. Three 100 MB clones take 0 MB of extra room on the disk, and spacetrace now says so where du still reports 400 MB. Use --no-clone-dedupe to turn it off.
  • On Windows, spacetrace now reads the space a file really occupies and counts a hard-linked file once, instead of falling back to the length the file claims.

0.3.0

· development milestone

Added

  • A running scan can be cancelled, and a subtree can be dropped from a loaded tree without invalidating the entries around it.
  • Sorting and drawing now name their measure explicitly, so a list that says largest first agrees with the number printed beside it.
  • Every push leaves a downloadable build behind, and install.sh installs it on Linux and macOS.

0.2.0

· development milestone

Added

  • spacetrace-agent: a read-only agent for servers and NAS boxes, with a built-in scheduler and an HTTP API. It never deletes anything.
  • Filesystem capacity, reported as free and total rather than a percentage full, because on APFS and thin pools a percentage disagrees with df.
  • The treemap layout engine: squarified tiles, level of detail, and hit-testing that follows the hierarchy.

Fixed

  • Opening a database no longer takes a write lock, so a read can no longer knock over a scan that is still writing.

0.1.0

· development milestone

Added

  • Scan a directory and see where the space went, with both measures side by side: what the files claim, and what the disk actually holds.
  • Snapshots stored in SQLite, so a scan taken today can be compared with one taken next month.
  • spacetrace diff names the folder responsible for a change instead of listing every file underneath it.
  • Export to the ncdu format, so a spacetrace snapshot can be opened by tools that already exist.
  • Symbolic links are not followed, hard links are counted once, and a sparse file reports what it allocates rather than the length it claims.

All releases · Download

Hub

0.5.1

Downloads and checksums

Fixed

  • A pushed snapshot is checked in full before it is stored: its tree must be sound and every value of the right type. One with a correct checksum and a broken tree used to be stored anyway, after which every page that read it failed; it is now refused with 400 and nothing of it is kept. A snapshot dated more than a day in the future is refused too, because it would have stayed the newest of its machine for good - so an agent whose clock is that far ahead now gets 400 on every push until its clock is fixed.

0.5.0

Downloads and checksums

Added

  • An alert rule can send email instead of calling a webhook. Type an address where the URL goes; a rule keeps exactly one destination, so there is nothing to get out of step. Mail is configured in an [smtp] section of the hub config file rather than in the dashboard, because the database is the file you back up and a password in it travels with every copy. A new Settings page shows the relay, never the password, and sends a test message through the same path an alert takes — so a success there means alerts will arrive, and a failure names what is wrong before a disk fills.
  • People, instead of one shared credential. A new People page issues a token per person with one of two roles: a viewer sees the whole fleet and can change none of it, an admin can change anything including who else has access. Alert rules now record who added them, which is the question a shared login could never answer. Tokens rather than passwords, on purpose — a generated token can be stored as a plain hash because there is nothing to guess, and a chosen password could not. The token in the hub's config file keeps working and stays an admin: it is the way back in, which is why the last admin cannot revoke themselves either.

0.4.0

Downloads and checksums

Added

  • A pushed snapshot is checked against the checksum it carries and refused with a 400 if it disagrees, instead of joining the fleet. A bit flipped in transit leaves a valid tree holding a wrong number — on a dashboard that sorts by urgency, that is the wrong machine at the top.

Changed

  • The hub's snapshot database moves to a new schema so the checksum has somewhere to live. Downgrading to an older build will no longer open the file — it says so plainly rather than misreading it. Putting a copy aside before upgrading costs nothing.

0.3.1

Downloads and checksums

Changed

  • The About page now lists released versions only. Entries that had landed but were in no release described work your copy does not contain.

0.3.0

Downloads and checksums

Added

  • The About page now shows which build is running (commit, build date and channel) and what changed in the last few releases.
  • /health reports the commit and the channel next to the version, so a running container can be identified without signing in.

Performance

  • Loading a large snapshot uses less memory, following the smaller tree representation in the scanning core.

0.2.0

· development milestone

Added

  • Downloadable binaries for Linux and macOS, and container images for both amd64 and arm64.

0.1.0

· development milestone

Added

  • A fleet dashboard: every agent and every root in one table, ordered by which one runs out of room first.
  • A growth trend and a forecast, which says plainly when there is not enough history to forecast anything.
  • Threshold alerts with a cooldown, delivered by webhook, plus agent tokens that can be issued and revoked from the dashboard.

All releases · Download