This document describes the architecture, file structure, data flow, and key technical decisions for the VoltPaste codebase. It is intended as a reference for AI coding agents and developers working on the project.
- Bundle ID:
com.chamika.VoltPaste - Platform: macOS 15.0+
- Language: Swift 6, SwiftUI, SwiftData
- Type: Menu bar agent (
LSUIElement = YES, no Dock icon) - Build: Xcode,
PBXFileSystemSynchronizedRootGroup— new files added underVoltPaste/are auto-included without modifyingproject.pbxproj
VoltPaste/
├── App/
│ ├── VoltPasteApp.swift # @main entry point, ModelContainer, Settings scene
│ └── AppDelegate.swift # NSStatusItem, PopupPanel, HotKeyManager wiring
├── Models/
│ ├── ClipboardItem.swift # SwiftData @Model for clipboard history entries
│ └── ContentType.swift # Enum: text | image | url | file | code
├── Services/
│ ├── ClipboardMonitor.swift # NSPasteboard polling (0.5s timer), dedup, storage
│ ├── HotKeyManager.swift # Carbon RegisterEventHotKey global shortcuts
│ ├── PasteService.swift # Write to pasteboard + simulate Cmd+V via CGEvent
│ ├── SoundManager.swift # AVAudioPlayer for clip.aiff, UserDefaults gate
│ └── LoginItemManager.swift # SMAppService.mainApp register/unregister
├── Views/
│ ├── PopupWindow/
│ │ ├── PopupPanel.swift # NSPanel subclass: floating, non-activating
│ │ ├── PopupView.swift # SwiftUI root view for the popup
│ │ └── ClipboardItemRow.swift# Single row: icon, preview, source app, time, actions
│ └── Settings/
│ ├── SettingsView.swift # TabView container
│ ├── GeneralSettingsView.swift
│ ├── SoundSettingsView.swift
│ ├── ShortcutSettingsView.swift
│ ├── ShortcutRecorder.swift # Custom key capture control using onKeyPress
│ └── DataSettingsView (inline in SettingsView)
├── Utilities/
│ └── Extensions.swift # Data.sha256Hash, NSImage helpers, Date.relativeString
└── Resources/
└── Sounds/
└── clip.aiff # Short click sound played on clipboard capture
VoltPasteApp (@main)
└── creates ModelContainer (SwiftData, persistent)
└── registers AppDelegate via @NSApplicationDelegateAdaptor
└── exposes only Settings scene (no WindowGroup)
└── deferred: calls appDelegate.setupClipboardMonitor(with:)
AppDelegate (NSApplicationDelegate)
├── setupStatusItem() → NSStatusItem in menu bar
├── setupHotKeys() → HotKeyManager.register(paste:pasteOriginal:)
└── setupClipboardMonitor() → ClipboardMonitor.startMonitoring()
HotKeyManagerfiresonPasteHotKeycallback on main queueAppDelegate.togglePopup()callsshowPopup()or closes existing panelcreatePopupPanel()buildsPopupViewwrapped inNSHostingViewinside aPopupPanelPopupPanel.showCentered()positions the panel, callsmakeKeyAndOrderFront(nil), installs event monitors- Panel closes on: Escape key, click outside, item selected, settings button pressed
- On close,
stopMonitoringEvents()removes allNSEventmonitors
NSPasteboard (system)
→ ClipboardMonitor (polls every 0.5s)
→ detectContentType() → ContentType
→ extractContent() → (Data, preview, thumbnail?)
→ SHA256 hash → dedup check via SwiftData #Predicate
→ insert ClipboardItem → ModelContext.save()
→ enforceLimit() → delete oldest unpinned if over cap
→ onNewItem?() → SoundManager.playClipSound()
User selects item in popup
→ PasteService.paste(item:asPlainText:)
→ NSPasteboard.clearContents() + write typed data
→ simulatePaste() → CGEvent Cmd+V after 0.1s delay
The popup requires careful keyboard event routing because multiple layers compete:
| Key | Handler | Mechanism |
|---|---|---|
| Up/Down arrow | PopupView |
.onKeyPress(.upArrow/.downArrow) on root VStack |
| Enter | PopupView |
.onKeyPress(.return) |
| Left/Right arrow | PopupView |
NSEvent.addLocalMonitorForEvents — required because TextField consumes these before SwiftUI sees them |
| Escape | PopupPanel |
NSEvent.addLocalMonitorForEvents in startMonitoringEvents() |
The selectionFromKeyboard flag in PopupView distinguishes keyboard navigation from hover-driven selection changes, preventing unwanted scroll-to on hover.
PopupPanel subclasses NSPanel with .nonactivatingPanel style mask. This allows the panel to receive key events (via canBecomeKey: true) without stealing focus from the previously active app — critical for Cmd+V to paste into the correct target.
Global NSEvent monitors require Accessibility permission and still don't fire reliably before the event reaches other apps. Carbon RegisterEventHotKey is the standard macOS approach for app-level global hotkeys and is more reliable.
ClipboardItem.content and thumbnailData use @Attribute(.externalStorage) so large binary blobs (images) are stored outside the SQLite database, keeping queries fast.
Before inserting a new clipboard item, the monitor hashes the raw data with CryptoKit SHA256 and queries for an existing item with the same contentHash. If found, only the timestamp is updated (moving it to the top of history). The #Unique macro enforces this at the database level.
The Settings window is an NSApp-level window managed by the SwiftUI Settings scene. Opening it from inside an NSPanel requires NSApp.activate(ignoringOtherApps: true) first and then calling the openSettings environment action. SettingsLink doesn't work inside NSPanel (causes ViewBridge error 18).
AXIsProcessTrustedWithOptions with the prompt option doesn't work under App Sandbox. Instead, the app uses NSWorkspace.shared.open(URL(string: "x-apple.systempreferences:...")) to direct the user to the correct System Settings pane.
| Key | Type | Default | Purpose |
|---|---|---|---|
pasteShortcutKeyCode |
Int | 9 (V) | Global paste popup hotkey — key code |
pasteShortcutModifiers |
Int | 0x1100 (Cmd+Shift) | Global paste popup hotkey — modifiers |
pasteOriginalShortcutKeyCode |
Int | 9 (V) | Paste as plain text hotkey — key code |
pasteOriginalShortcutModifiers |
Int | 0x900 (Cmd+Option) | Paste as plain text hotkey — modifiers |
maxHistoryItems |
Int | 500 | Maximum unpinned items retained |
soundEnabled |
Bool | true | Play clip.aiff on clipboard capture |
startAtLogin |
Bool | false | SMAppService login item registration |
Tests live in VoltPasteTests/VoltPasteTests.swift and use the Swift Testing framework (@Test, #expect).
Test groups:
ContentTypeTests— enum rawValue round-trips, display names, system imagesDataExtensionTests— SHA256 determinism, empty data, consistencyDateExtensionTests—relativeStringoutput for recent/old datesClipboardItemModelTests— model initialisation, field defaultsHotKeyComboTests— default combos, equalityLoginItemManagerTests— initial state assertion
Run with: Cmd+U in Xcode, or xcodebuild test -scheme VoltPaste.
- Add a case to
ContentTypeinModels/ContentType.swift— providedisplayName,systemImage,tintColor - Handle detection in
ClipboardMonitor.detectContentType(pasteboard:) - Handle extraction in
ClipboardMonitor.extractContent(pasteboard:type:) - Handle paste writing in
PasteService.paste(item:asPlainText:) - Optionally handle preview display in
ClipboardItemRow.contentPreview