Imported from milan0x/local-cloud-browser (
AGENTS.md). Install upstream withnpx skills add milan0x/local-cloud-browser. Copyright stays with the author.
Local Cloud Browser — Project Guide
Overview
Native macOS SwiftUI application for managing AWS-compatible endpoints. Provides a GUI for browsing and interacting with cloud services (S3, SQS, SNS, Secrets Manager).
Tech Stack
- Language: Swift 6.0
- UI: SwiftUI, macOS 14+
- Build: Xcode project (
Local Cloud Browser.xcodeproj) using PBXFileSystemSynchronizedRootGroup — files auto-discovered, no manual target membership - Architecture: Module-based with enum-driven routing
Project Structure
LocalCloudBrowser/
├── App/ — Entry point, global state, command menus
├── Navigation/ — Sidebar, content shell, route enum
├── Modules/ — Service modules (protocol + per-service views) + Donation panel
├── Safety/ — Endpoint validation, read-only interceptor
├── Networking/ — HTTP client + SigV4 signing
└── Settings/ — Connection configuration model
Key Files
App/AppState.swift— Global ObservableObject; holds connection state, endpoint, read-only flag, selected routeApp/HelpCommands.swift— AllCommandsfor the menu bar (File, Connection, Donation, Help) + FocusedValueKeysNavigation/Route.swift— Enum of all navigable servicesNavigation/ContentView.swift— Main NavigationSplitView shell; owns the donation sheet binding and the floating heart overlayModules/ServiceModule.swift— Protocol all service modules conform toModules/Donation/— Donation panel: addresses, runtime QR generator, modal view, bottom-trailing heart buttonSafety/SafetyGuard.swift— Validates endpoints are localNetworking/CloudClient.swift— Async HTTP client with read-only guardNetworking/SigV4Signer.swift— AWS SigV4 request signing (used for non-local endpoints)
Conventions
- All UI state flows through
AppStatevia@EnvironmentObject - New services: add a case to
Route, create aModules/<Service>/directory with a view, wire it inContentView.detailView(for:) - Read-only mode defaults to on — mutating HTTP methods are blocked unless toggled off
- Endpoint safety: non-local endpoints show a warning banner in the sidebar
- Swift concurrency: use
@MainActorfor UI-bound classes
Build & Run
xcodebuild -project "Local Cloud Browser.xcodeproj" -scheme LocalCloudBrowser -configuration Debug build
# or open in Xcode and ⌘R
Distribution
Shipped outside the App Store as a signed + notarized DMG. App Store is not the target — no IAP, no per-feature paywalls; the app is free with full features.
- Signing identity:
Developer ID Application: Milan Karakaya (MQXW376WC6)(in login keychain) - Notarization profile:
notarytool(xcrun notarytoolkeychain profile in login keychain) - Release flow (fully CLI — no Xcode GUI needed; commit + push first so the tag matches the binary):
xcodebuild archive -project "Local Cloud Browser.xcodeproj" -scheme LocalCloudBrowser -configuration Release -archivePath <dir>/LCB.xcarchivexcodebuild -exportArchive -archivePath <dir>/LCB.xcarchive -exportOptionsPlist <plist> -exportPath <dir>/exportwith plist keysmethod=developer-id,teamID=MQXW376WC6,signingStyle=automatic,destination=export- Notarize + staple the app:
ditto -c -k --keepParent <app> app.zip→xcrun notarytool submit app.zip --keychain-profile notarytool --wait→xcrun stapler staple <app> - Stage
.app+ Applications symlink into a folder, thenhdiutil create -volname "Local Cloud Browser" -srcfolder <stage> -format UDZO LocalCloudBrowser-<version>.dmg codesign --sign "Developer ID Application: Milan Karakaya (MQXW376WC6)" --options runtime --timestamp <dmg>xcrun notarytool submit <dmg> --keychain-profile notarytool --wait→xcrun stapler staple <dmg>spctl --assess --type open --context context:primary-signature -v <dmg>should printaccepted, source=Notarized Developer IDgh release create v<version> <dmg> --target "$(git rev-parse HEAD)" --title "v<version>" --latest --notes "..."— one release per version, tagged at the exact commit the binary was built from, so the auto-generated Source code archives match the DMG. (README links to/releases/latest, which follows automatically.)- (optional)
gh workflow run bump.yml -R milan0x/homebrew-tap— bumps the Homebrew cask immediately; the tap's scheduled workflow picks up new releases within 6 hours on its own either way.
- Homebrew: cask
local-cloud-browserlives inmilan0x/homebrew-tap(local checkout:~/dev/homebrew-tap). Itsbump.ymlworkflow polls the latest GitHub release every 6h and updates version + sha256 automatically — no manual edits needed. - Release naming (MUST — Homebrew depends on it): tag exactly
v<version>, DMG asset exactlyLocalCloudBrowser-<version>.dmg, and the app bundle inside the DMG exactlyLocal Cloud Browser GUI.app. The tap's bump workflow and cask build the download URL and app path from these; any deviation silently breaksbrew install. - Both the
.appand the.dmgare notarized and stapled, so download → mount → open → run is warning-free even offline. - Version lives in the project file (
MARKETING_VERSION/CURRENT_PROJECT_VERSION); the About panel reads it from the bundle at runtime.
Build & Test Rules
After Every Code Change
- Run the xcodebuild command above after modifying any file under
LocalCloudBrowser/. Always rebuild so the binary stays current. - If the build fails, fix compilation errors before moving on.
- SourceKit LSP diagnostics are noise — verify with actual
xcodebuild.
After Completing a Task
- A test scheme is not yet wired into the Xcode project (tests live under
Tests/but cannot be run viaxcodebuild testuntil a test target is added). Skip the run-tests step until the scheme is fixed. - Do NOT write new tests unless explicitly asked to.
What Is Testable (Unit Tests Only)
Tests cover pure logic only — code that takes input and returns output with no UI dependency:
- Parsers:
SNSXMLParser,S3XMLParser,ServiceError.parse,JSONHelperParser - Model computed properties:
SQSMessage.bodyType,.truncatedId,S3Object.isFolder, etc. - CLI helpers:
.toAWSCLI(),.sendMessageCLI(), shell escaping - Safety:
SafetyGuard.evaluate(),ReadOnlyInterceptor.allowsRequest() - Codable models: encode/decode round-trips
- Static utility functions: URL rewriting, form encoding, region validation
What Is NOT Testable (Never Write Tests For These)
- SwiftUI views (
View,body, modifiers, sheets, alerts, toolbars) @StateObject,@EnvironmentObject,@State,@BindingObservableObjectclasses that depend onAppStateor UI lifecycle- Anything requiring a running app, window server, or user interaction
NSViewRepresentablewrappers (CodeTextEditor,PaneClickDetector, etc.)
Design Context
Users
Individual developers and small DevOps/platform teams who manage local AWS-compatible services (LocalStack, MinIO) during development. They use the app as a daily companion while building and debugging — it needs to stay out of the way and just work.
Brand Personality
Professional, clear, reliable. Quiet confidence, zero theatrics. Clarity of information, predictable behavior, and consistency above all. Friendly without being playful, capable without being showy.
Aesthetic Direction
- Visual tone: Native macOS, utilitarian, polished but restrained
- References: Proxyman, TablePlus, Xcode, Instruments
- Anti-references: Electron apps, AWS Console density, generic SaaS dashboards
- Theme: System appearance (light + dark via semantic SwiftUI colors)
- Typography: System fonts only (SF Pro, SF Mono)
- Iconography: SF Symbols exclusively
Design Principles
- Clarity over cleverness: Communicate, don't decorate. No fancy UI/UX tricks.
- Native and invisible: Follow macOS HIG faithfully. Feel like it ships with the OS.
- Safety by default: Read-only on, endpoint validation, confirmation for destructive actions.
- Consistency across modules: All service modules feel identical via shared components.
- Information density, not overload: Progressive disclosure to layer information.