Skip to content

hex/Stash

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

71 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Stash icon

Stash

A lightweight macOS clipboard history manager that lives in your menu bar.
Captures text, rich text, images, URLs, and file paths with zero dependencies.

macOS 14+ Swift 6 MIT License


Features

  • Clipboard monitoring -- polls the system pasteboard every 0.3s and captures all content types
  • Menu bar popover -- translucent frosted-glass popover with colored content-type badges and divider-separated entries
  • Image thumbnails -- inline image previews in the entry list, with a preview button to open full images
  • Context menus -- right-click any entry to Copy, Pin/Unpin, Preview (images), or Delete
  • Encrypted storage -- all clipboard content is AES-256-GCM encrypted at rest with a Keychain-stored key
  • Animated capture feedback -- the menu bar icon flashes when a new entry is recorded
  • Password manager filtering -- automatically skips entries from 1Password, KeePassXC, and other apps that mark clipboard content as concealed or transient
  • App exclusion -- block specific apps from being recorded, with a running apps picker for easy selection
  • Consecutive dedup -- identical back-to-back copies are stored once
  • Pinned entries -- pinned entries are protected from history limit pruning
  • Auto-expiry -- optionally delete entries older than 24 hours, 7 days, or 30 days
  • Clear on quit -- optionally wipe all history when the app terminates
  • Time Machine exclusion -- the SwiftData store is excluded from backups
  • Rich text paste -- pastes RTF content with a plain text fallback for maximum compatibility
  • Source app detection -- identifies the source app via window stacking order, handling non-activating panels like iTerm's quake window
  • Right-click to pause -- right-click the menu bar icon to toggle recording
  • Launch at login -- uses the modern SMAppService API
  • Auto-update -- checks for updates via Sparkle, with one-click install from GitHub Releases

Install

brew install --cask hex/tap/stash

Build from Source

Prerequisites:

Requirement Minimum
macOS 14.0 (Sonoma)
Xcode 16.0
XcodeGen 2.38
brew install xcodegen     # if not installed
cd Stash
xcodegen generate
open Stash.xcodeproj      # build and run with Cmd+R

Or build from the command line:

cd Stash
xcodegen generate
xcodebuild -scheme Stash -configuration Debug build

Usage

Menu Bar

Click the clipboard icon in the menu bar to open a translucent popover showing your recent clipboard entries. Each entry shows:

  • Colored badge indicating content type (gray for text, purple for images, blue for URLs, yellow for files)
  • Preview text (up to 2 lines) or image thumbnail
  • Source app name (bold) and human-friendly timestamp

Click any entry to paste it. Right-click for context menu actions (Copy, Pin, Delete, Preview). Right-click the menu bar icon to toggle pause.

Settings

Open via the gear icon in the popover. Configurable options:

Setting Default Range
History limit 500 10 - 10,000 entries
Launch at login Off --
Excluded apps None Pick from running apps or enter bundle IDs
Retention Forever Never / 24 hours / 7 days / 30 days
Clear history on quit Off --

The Privacy section also has a Clear All History button.

Privacy

Stash automatically skips clipboard content marked with privacy indicators:

  • org.nspasteboard.ConcealedType (industry standard)
  • org.nspasteboard.TransientType (transient content)
  • org.nspasteboard.AutoGeneratedType (auto-fill)
  • 1Password and KeePassXC-specific markers

You can also exclude specific apps entirely from recording via Settings.

Encryption: All clipboard content fields (text, URLs, file paths, images, rich text) are encrypted at rest using AES-256-GCM. The symmetric key is stored in the macOS Keychain with device-only access (kSecAttrAccessibleWhenUnlockedThisDeviceOnly).

Time Machine: The SwiftData store directory is excluded from Time Machine backups.

The app is not sandboxed and stores clipboard history locally via SwiftData. No data is sent to any server.

Architecture

NSPasteboard.general (polled every 0.3s)
    |
ClipboardMonitor -- detect change, identify source app, filter, classify
    |
AppController -- orchestrates all services
    |
StorageManager + CryptoService -- encrypt, persist, decrypt, dedup
    |
MenuBarView -- observe StorageManager.changeCount
    |
PasteService -- write entry back to pasteboard

AppController (@MainActor @Observable) owns all services and wires them together with closures. All services run on the main actor (required by SwiftData's ModelContext and AppKit's NSPasteboard).

The app uses a custom NSStatusItem + NSPopover rather than SwiftUI's MenuBarExtra to support animated icon transitions and live-updating views.

Source app detection uses CGWindowListCopyWindowInfo to find the topmost on-screen window by stacking order. This correctly identifies the source app even for non-activating panels (e.g. iTerm's quake window) that don't register as frontmostApplication.

Project Structure

Stash/
├── project.yml                 # XcodeGen configuration (source of truth)
├── Stash/
│   ├── StashApp.swift          # Entry point + AppController
│   ├── Model/
│   │   ├── ClipboardEntry.swift    # SwiftData model
│   │   └── ContentType.swift       # Content type enum + detection
│   ├── Services/
│   │   ├── ClipboardMonitor.swift  # Pasteboard polling + source app detection
│   │   ├── StorageManager.swift    # SwiftData persistence + encryption
│   │   └── PasteService.swift      # Paste-from-history
│   ├── Views/
│   │   ├── MenuBarView.swift       # Translucent popover with entry list and controls
│   │   ├── EntryRowView.swift      # Entry row with colored badge and content preview
│   │   └── SettingsView.swift      # Preferences UI
│   └── Support/
│       ├── CryptoService.swift     # AES-256-GCM encryption + Keychain key storage
│       ├── Preferences.swift       # UserDefaults wrapper
│       ├── PasteboardConstants.swift
│       └── UpdaterController.swift # Sparkle auto-update integration
└── StashTests/                 # 88 tests across 7 files
    ├── Model/
    ├── Services/
    └── Support/

Testing

cd Stash
xcodebuild test -scheme Stash -destination 'platform=macOS'

Or press Cmd+U in Xcode. Tests use in-memory SwiftData containers and named pasteboards for isolation.

Versioning

Stash uses calendar versioning: YYYY.M.PATCH

  • YYYY -- release year
  • M -- release month (unpadded)
  • PATCH -- incremental patch within the month, starting at 0

Examples: 2026.2.0, 2026.2.1, 2026.12.0

The build number (CFBundleVersion) is an incrementing integer independent of the version string.

License

MIT

About

macOS clipboard history manager

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages