A privacy-first clipboard manager for Mac — with seamless iPhone sync.
No cloud. No subscription. No tracking. Just your clipboard, organized.
| Feature | |
|---|---|
| 📋 | Auto-capture — monitors your clipboard and instantly saves text, URLs, and images |
| 🗂️ | Collections — organize clips into named, emoji-tagged groups |
| ⚡ | Paste & Delete — customizable hotkey that pastes the top item and removes it from the pile |
| 🔍 | Full-text search — find anything across all collections instantly |
| 📱 | iPhone companion — a native iOS app that stays in sync with your Mac |
| 🔄 | LWW-CRDT sync — conflict-free, serverless sync over your local Wi-Fi via Bonjour |
| 🖼️ | Image support — capture and paste screenshots, photos, and image files |
| 🔗 | URL enrichment — automatically fetches page title and metadata for web links |
| 🗄️ | Archive — keep old collections out of the way without deleting them |
| 🔒 | 100% local — your data never leaves your devices |
Coming soon — build the project and see for yourself.
Pile is intentionally simple. Zero third-party dependencies — only Apple frameworks.
clipboardVault/
├── ClipboardVault/ # macOS app (MenuBar + main window)
│ └── pileMac/
│ ├── PileApp.swift # App entry, hotkey & paste logic
│ ├── ClipboardMonitor.swift # NSPasteboard polling (0.8s)
│ ├── Database/
│ │ └── PileDatabase.swift # Raw SQLite3 — no ORM
│ ├── Store/
│ │ └── PileStore.swift # Observable state + LWW merge
│ ├── Services/
│ │ ├── SyncServer.swift # Bonjour TCP server (NWListener)
│ │ ├── HotkeyManager.swift # Global hotkey via CGEvent
│ │ ├── ImageStorage.swift # Disk-based image cache
│ │ └── URLMetadataFetcher.swift
│ └── Views/ # SwiftUI views
│
└── PileMobile/ # iOS companion app
├── PileMobile/
│ ├── MobileStore.swift # App Group JSON persistence
│ └── SyncClient.swift # Bonjour TCP client (NWBrowser)
└── PileShare/ # Share Extension
Pile uses a serverless LWW-CRDT (Last-Write-Wins Conflict-free Replicated Data Type) sync over Bonjour/mDNS — the same technology used by AirDrop and AirPlay.
Mac (NWListener on port 8765) ←──Bonjour──→ iPhone (NWBrowser)
│ │
fullState ──────────────────────────────────────► merge
merge ◄──────────────────────────────────── fullState
│ │
itemAdded / itemDeleted / collectionUpdated (delta)
- No internet required — works entirely on your local network
- Tombstones ensure deletions propagate correctly across devices
updatedAttimestamps determine which version wins on conflict
| Minimum | |
|---|---|
| macOS | 14.0 Sonoma |
| iOS | 17.0 |
| Xcode | 15.0 |
| Swift | 5.9 |
1. Clone the repository
git clone https://github.com/YOUR_USERNAME/pile.git
cd pile2. Open the macOS project
open ClipboardVault/ClipboardVault.xcodeproj3. Open the iOS project (separate Xcode window)
open PileMobile/PileMobile.xcodeproj4. Configure signing
In Xcode, for each target:
- Select your Team under Signing & Capabilities
- Update the Bundle Identifier to something unique (e.g.
com.yourname.pile)
⚠️ The iOS app and Share Extension must share the same App Group ID. UpdatePileAppGroup.idin both targets to match your own group identifier (e.g.group.com.yourname.pile).
5. Build & Run
- macOS: Select
pileMacscheme → Run (⌘R) - iOS: Select
PileMobilescheme, choose your device → Run (⌘R)
Both apps must be on the same Wi-Fi network for sync to work.
Pile requires the following permissions:
| Permission | Why |
|---|---|
| Accessibility | Required to simulate ⌘V for the Paste & Delete feature |
| Local Network | Required for Bonjour discovery between Mac and iPhone |
Pile never requests internet access, location, contacts, or any other sensitive permission.
ClipboardMonitor polls NSPasteboard.changeCount every 0.8 seconds. When a change is detected, it classifies the content as image, URL, or text and fires a callback. Internal copies (e.g. during Paste & Delete) are suppressed to avoid circular captures.
When the hotkey fires:
- The target app's PID is captured before Pile's window gains focus
- The top item's content is written to
NSPasteboard - The target app is activated
- A
CGEventsimulates ⌘V keyboard input (requires Accessibility permission) - The original clipboard contents are restored after 500ms
- The item is deleted from the collection (if the setting is enabled)
Every item and collection carries a updatedAt timestamp. On connection:
- Both devices exchange their full state (including soft-deleted tombstones)
- For each record, the version with the later
updatedAtwins - Subsequent changes are broadcast as delta messages in real time
Contributions are welcome! Feel free to:
- 🐛 Open an issue for bugs or unexpected behaviour
- 💡 Suggest a feature via GitHub Discussions
- 🔧 Submit a pull request
Please keep PRs focused — one feature or fix per PR.
Pile is released under the MIT License. See LICENSE for details.