git clone https://github.com/yourusername/cacheout.git
cd cacheout
swift buildSee ARCHITECTURE.md for the full architecture overview.
Key directories:
Sources/Cacheout/Models/— Data typesSources/Cacheout/Scanner/— Scanning logic (actors)Sources/Cacheout/Cleaner/— Cleanup logic (actor)Sources/Cacheout/ViewModels/— State managementSources/Cacheout/Views/— SwiftUI views
- Edit
Sources/Cacheout/Scanner/Categories.swift - Add a new
CacheCategory(...)in the appropriate MARK section:
CacheCategory(
name: "Your Tool Cache",
slug: "your_tool_cache", // lowercase, underscored
description: "Short description for UI.",
icon: "sf.symbol.name", // SF Symbol
discovery: [
.probed(
command: "your-tool --cache-dir 2>/dev/null",
requiresTool: "your-tool",
fallbacks: ["Library/Caches/YourTool"]
)
],
riskLevel: .safe, // .safe, .review, or .caution
rebuildNote: "What happens after cleaning",
defaultSelected: true // true only for .safe
)- Build and test:
swift build && .build/debug/Cacheout --cli scan - Verify the category appears in scan output with correct size
Guidelines:
- Set
riskLevelconservatively — when in doubt, use.review - Always provide fallback paths for probed categories
- Set
requiresToolwhen the probe command depends on a specific binary - Use 2-second timeout-safe commands in probes (avoid interactive prompts)
- Probe commands should include
2>/dev/nullto suppress stderr
- Create the file in
Sources/Cacheout/Views/ - Accept
CacheoutViewModelvia@EnvironmentObject - Follow existing naming conventions (no suffixes for primary views,
Sheetsuffix for modals) - Add file-level documentation comment explaining the view's purpose and layout
The CacheoutViewModel is @MainActor isolated. All @Published properties
update the UI automatically. When adding new state:
- Add the
@Publishedproperty - If persisted, add a
didSetobserver that writes to UserDefaults - If loading from UserDefaults, initialize in
init() - Add computed properties for derived state rather than duplicating data
- Concurrency: Use actors for thread-safe business logic,
@MainActorfor view models - Error handling: Collect errors rather than throwing — return them in reports
- File organization: Use
// MARK: -sections within files - Access control: Default to internal; use
privatefor implementation details - Documentation: File-level
///doc comments explaining purpose and behavior
- Files: PascalCase matching the primary type (
CacheScanner.swift) - Types: PascalCase (
CacheCategory,ScanResult) - Properties/methods: camelCase (
scanResults,toggleSelection) - Slugs: lowercase with underscores (
xcode_derived_data) - SF Symbols: Use descriptive symbol names (
hammer.fill,shippingbox.fill)
- Views never access scanners/cleaners directly — always through the view model
- Actors handle all filesystem operations
- No force unwrapping except in controlled situations (e.g., known-good data)
- Shell commands always have timeouts (2s for probes, 30s for clean commands)
- Notification APIs always guarded by
canUseNotificationscheck
Currently no automated tests. When adding tests:
- Test scanners with mock filesystem
- Test view model state transitions
- Test CLI output format
- Test path discovery with mock environment
- Fork the repository
- Create a feature branch:
git checkout -b feature/your-feature - Make your changes with clear commit messages
- Ensure
swift buildsucceeds - Test both GUI and CLI modes
- Submit a PR with a clear description of changes
MIT — See LICENSE