This guide is for developers (including AI assistants) working on Cloak.
Cloak is a macOS privacy app that creates a shareable window for video calls. Instead of sharing your actual screen, you share the Cloak window, which can display a privacy overlay when needed.
- Language: Swift
- Framework: AppKit (NOT SwiftUI)
- Screen Capture: ScreenCaptureKit
- Global Hotkeys: Carbon.HIToolbox
- Minimum macOS: 14.0
| File | Purpose |
|---|---|
Cloak/AppDelegate.swift |
Main application code (~1200 lines, contains all classes) |
Cloak/main.swift |
App entry point (manual NSApplication setup) |
Cloak/Info.plist |
App configuration and permissions |
Cloak.xcodeproj/project.pbxproj |
Xcode project settings |
All code is in AppDelegate.swift for simplicity:
AppDelegate.swift
├── AppDelegate (main app controller)
├── HotkeyManager (global hotkey registration)
├── HotkeyAction (enum for hotkey actions)
├── HotkeyConfig (hotkey configuration struct)
├── MainView (main window content)
├── StartScreenView (settings UI before capture)
├── PreviewView (displays captured screen)
├── ScreenCaptureEngine (handles screen capture)
├── PrivacyMode (enum: blur, image, black)
└── HUDWindow (floating notification window)
Always read AppDelegate.swift before making changes:
# Read the full file to understand the current implementation
cat Cloak/AppDelegate.swiftThis is an Xcode project, NOT Swift Package Manager:
# Build the project
xcodebuild -project Cloak.xcodeproj -scheme Cloak -configuration Debug build
# Clean build (use when having issues)
xcodebuild clean -project Cloak.xcodeproj -scheme Cloak
rm -rf ~/Library/Developer/Xcode/DerivedData/Cloak-*# Check git status
git status
# Check if there are uncommitted changes
git diff
# Check recent commits for context
git log --oneline -10- All code goes in AppDelegate.swift - This is a small app, no need to split files
- Use AppKit, not SwiftUI - The app uses NSWindow, NSView, etc.
- Mark sections with
// MARK: -for organization - Use UserDefaults for persistence - Simple key-value storage
Adding a new setting:
- Add property to relevant class (usually
StartScreenView) - Add UI in
setupUI()method - Add load logic in
loadSettings() - Add save logic (usually via UserDefaults)
- Use the setting where needed
Adding a new hotkey action:
- Add case to
HotkeyActionenum - Update
displayNameandstorageKeycomputed properties - Handle the action in
AppDelegate.hotkeyDidTrigger()
Modifying screen capture:
- Changes go in
ScreenCaptureEngineclass setupStream()configures what gets capturedSCContentFiltercontrols what's included/excluded
# Quick build test
xcodebuild -project Cloak.xcodeproj -scheme Cloak -configuration Debug build CONFIGURATION_BUILD_DIR=./build-test 2>&1 | grep -E "(error:|warning:|BUILD)"
# Run the app
open ./build-test/Cloak.app
# Or build and run in one command
xcodebuild -project Cloak.xcodeproj -scheme Cloak -configuration Debug build CONFIGURATION_BUILD_DIR=./build-test && open ./build-test/Cloak.app# Ensure it compiles
xcodebuild -project Cloak.xcodeproj -scheme Cloak -configuration Debug build CONFIGURATION_BUILD_DIR=./build-test 2>&1 | grep -E "(error:|BUILD)"- Launch the app and verify your changes work
- Test edge cases (what happens if user does X?)
- Test persistence (quit and relaunch, are settings saved?)
If you added features, update:
README.md- User-facing documentationCHANGELOG.md- Add entry under[Unreleased]DISTRIBUTION.md- If build/release process changed
# Check what changed
git status
git diff
# Stage and commit with descriptive message
git add .
git commit -m "Add feature X
- Detail 1
- Detail 2
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <assistant_name> <noreply@anthropic.com>"The app is not code-signed. If you see signing errors:
# Build without signing
xcodebuild ... CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED=NO CODE_SIGNING_ALLOWED=NOXcode cached old build. Clean DerivedData:
rm -rf ~/Library/Developer/Xcode/DerivedData/Cloak-*
xcodebuild clean -project Cloak.xcodeproj -scheme CloakThe window needs to be visible and on-screen. Make sure:
- Window is not minimized
- Window is on the current desktop/space
Global hotkeys use Carbon APIs which require:
- The app to be running
- Hotkeys registered via
RegisterEventHotKey - Event handler installed via
InstallEventHandler
If capture isn't working:
- Check System Settings > Privacy & Security > Screen Recording
- Ensure Cloak is listed and enabled
- Restart the app after granting permission
See DISTRIBUTION.md for full details. Quick summary:
./scripts/build-release.sh 1.0.0
# Creates dist/Cloak-1.0.0.dmggit tag -a v1.0.0 -m "Release v1.0.0"
git push origin main
git push origin v1.0.0
# GitHub Actions creates the release automaticallyCloak/
├── .github/
│ └── workflows/
│ └── release.yml # GitHub Actions for automated releases
├── Cloak/
│ ├── AppDelegate.swift # All application code
│ ├── main.swift # App entry point
│ └── Info.plist # App configuration
├── Cloak.xcodeproj/ # Xcode project
├── scripts/
│ └── build-release.sh # Local release build script
├── CHANGELOG.md # Version history
├── DEVELOPMENT.md # This file
├── DISTRIBUTION.md # Build and release guide
├── LICENSE # MIT License
└── README.md # User documentation
- Always read before writing - Read the relevant code section before making edits
- Test builds frequently - Run xcodebuild after changes to catch errors early
- Use the todo list - Track multi-step tasks with TodoWrite
- Commit incrementally - Make focused commits after each feature/fix
- Update CHANGELOG.md - Add entries for user-visible changes
- The user is a TypeScript dev - Explain Swift/macOS concepts when relevant