Imported from stefanovskyi/disk_inspection (
AGENTS.md). Install upstream withnpx skills add stefanovskyi/disk_inspection. Copyright stays with the author.
AGENTS.md
Project
SpaceLens is a native SwiftUI disk-inspection utility for macOS 14 and newer. It discovers mounted volumes, measures filesystem usage, and presents the results as an interactive sunburst chart and an accessible ranked list.
Keep the product name SpaceLens. The DaisyDisk screenshots supplied during initial development are visual references only; do not copy DaisyDisk branding, proprietary assets, or exact layouts.
Repository Map
Package.swift— Swift Package Manager manifest.Sources/SpaceLens/SpaceLensApp.swift— application entry point and menu commands.Sources/SpaceLens/Models/— filesystem, volume, scan, and chart-layout data models.Sources/SpaceLens/Models/ScanSessionStore.swift— in-memory scan cache and selected-folder session models keyed by standardized path.Sources/SpaceLens/Services/DiskScanner.swift— asynchronous recursive filesystem scanner.Sources/SpaceLens/Services/VolumeDiscovery.swift— mounted-volume discovery.Sources/SpaceLens/ViewModels/AppViewModel.swift— application state, navigation, scanning, and macOS actions.Sources/SpaceLens/Views/— SwiftUI interface and interactive sunburst chart.Sources/SpaceLens/Support/— formatting and design tokens.Tests/SpaceLensTests/— XCTest coverage for scanner and chart layout.Scripts/run_self_tests.sh— framework-free tests for Command Line Tools installations.Scripts/package_app.sh— release build,.appassembly, and stable-identity signing with an ad-hoc fallback.Scripts/resolve_signing_identity.sh— selects the configured or local development signing identity.Support/Info.plist.in— app-bundle metadata template.dist/SpaceLens.app— generated app bundle; do not edit by hand.
Required Commands
Run these from the repository root:
make build
make test
make app
make testis the required minimum verification after changes to scanning, models, or chart layout.- Run
make buildafter all source changes. - Run
make appwhen changing app code, bundle metadata, or packaging behavior. - Full Xcode installations may additionally run
swift testor the XCTest target in Xcode.
Some Command Line Tools installations have a mismatched default SDK. On such machines, select a compatible SDK explicitly:
SDKROOT=/Library/Developer/CommandLineTools/SDKs/MacOSX15.5.sdk swift build
SPACELENS_SDK_PATH=/Library/Developer/CommandLineTools/SDKs/MacOSX15.5.sdk make test
Do not hard-code this compatibility override into application source code.
Filesystem Safety
- SpaceLens is read-only. Never add deletion, moving, cleanup, or automatic file-modification behavior unless the user explicitly requests it.
- Never follow symbolic links during scanning. This prevents cycles and avoids measuring data outside the selected root.
- Stay on the selected filesystem. Main-disk scans must skip
/System/Volumesand/Volumes, and directory device/inode identities must prevent APFS firmlink duplication. - Permission errors must be collected and shown as unreadable/protected items; one inaccessible path must not abort an otherwise valid scan.
- Scans must remain cancellable and must not block the main actor.
- Run independent filesystem subtrees through a bounded concurrency limiter. Never create an unbounded task per file or directory.
- Detached scan workers must be wrapped in a cancellation handler; cancelling or replacing a scan must terminate its worker.
- Provider-backed subtrees must be isolated behind a no-progress timeout. A filesystem call that stops responding must be reported as unreadable and must not freeze the remainder of the scan.
- Use allocated file size when available, falling back to logical file size.
- Treat mounted-volume notifications as refresh signals. Do not automatically begin an expensive scan when a disk is mounted.
- Preserve the Full Disk Access explanation. macOS privacy restrictions are expected and are not application failures.
- Gate startup-disk scans on the Full Disk Access preflight. The user must be able to open the macOS privacy pane, cancel, or explicitly continue with current access; folder scans must not be gated.
Architecture and State
- Keep filesystem traversal in
DiskScanner, mounted-disk enumeration inVolumeDiscovery, and UI state inAppViewModel. - Perform filesystem work in a detached background task and publish UI changes on the main actor.
FileNode.idis its standardized path. Avoid random identifiers that would destabilize hover, list, or navigation state.- Keep sunburst geometry in
SunburstLayoutseparate from Canvas rendering so it remains independently testable. - At a volume root, scale the sunburst sweep to used capacity and leave the remaining angle transparent as labeled free space. Folder-only scans use the full circle.
- Sunburst angular width represents byte size; radial level and branch reach represent hierarchy depth. Never fill missing descendants with opaque background rings.
- A navigation path must always start with the current scan root. Breadcrumb navigation truncates this path; drilling into a directory appends to it.
- Starting a new scan must cancel or invalidate the previous scan so stale results cannot replace newer results.
- Retain completed disk and selected-folder scans in
ScanSessionStorefor the app session. Returning home clears the current presentation, not the cache; selecting a cached location must offer view or rescan instead of scanning immediately. - Keep picker-selected folders in the sidebar until removed or the app quits. Removing a folder from the sidebar clears only its session entry and cached scan; it must never modify the folder on disk.
- Retain at most
DiskScanner.retainedChildLimitdirect children per directory. Preserve byte and item totals through the syntheticSmaller itemsaggregate. - Throttle progress delivery by elapsed time. The visual spinner must animate independently of filesystem progress events.
- Show elapsed time during a scan and preserve the completed scan duration in the results header.
UI Conventions
- Use native SwiftUI and AppKit APIs; avoid third-party dependencies unless clearly justified.
- Use SF Symbols for interface icons. Do not use emoji as icons.
- Support both light and dark appearances through
SpaceTheme. - The chart must provide hover feedback, click-to-drill behavior, and context actions without layout shifts.
- Color cannot be the only way to understand storage data. Maintain the ranked textual item list and accessibility labels.
- Continuous loading animation must respect
accessibilityReduceMotionand expose a textual accessibility value. - Every clickable icon-only control needs an accessibility label or useful help text.
- Keep Finder and Terminal actions available from both the chart/list context menus and the current-folder inspector.
- Preserve a minimum usable window size of approximately 1100 × 620 points unless adding a genuinely adaptive compact layout.
Tests
Add or update tests when changing:
- symbolic-link handling;
- size aggregation and child sorting;
- scan progress or cancellation;
- bounded parallel traversal;
- unreadable-item behavior;
- stalled provider-directory behavior;
- sunburst proportions, depth limits, or hierarchy;
- navigation-path semantics.
If XCTest is unavailable in the active Command Line Tools installation, update the matching checks in Scripts/SelfTests.swift and verify with make test.
Packaging
Scripts/package_app.shmust remain deterministic and may only replacedist/SpaceLens.app.- Keep the executable name, bundle name, and
CFBundleExecutablesynchronized asSpaceLens. - Validate packaged changes with:
codesign --verify --deep --strict --verbose=2 dist/SpaceLens.app
plutil -lint dist/SpaceLens.app/Contents/Info.plist
- Prefer a stable code-signing identity for builds that use privacy-protected resources. The packaging script automatically selects
SpaceLens Local Development, acceptsSPACELENS_CODESIGN_IDENTITY, and otherwise warns before falling back to ad-hoc signing. - Distribution outside the local machine requires a Developer ID certificate, hardened runtime, and notarization; do not claim a local or self-signed build is notarized.
Change Discipline
- Preserve unrelated user changes.
- Prefer small, focused Swift types and testable pure functions.
- Do not edit generated files in
.build/ordist/manually. - Update
README.mdwhen supported macOS versions, permissions, commands, or user-facing features change.