# pbring
Secure macOS clipboard history daemon. Encrypted, headless, pipe-first.
Like [cliphist](https://github.com/sentriz/cliphist), but for macOS.
*pasteboard + ring -- stores copy history in an encrypted ring buffer, like Emacs kill-ring.*
## Features
- AES-256-GCM per-entry encryption with key stored in macOS Keychain
- Automatic filtering of passwords (1Password, Keychain, etc.) via NSPasteboard markers
- Loop prevention via `org.nspasteboard.source`
- TTL-based auto-expiry (default: 24h)
- Memory safety with `zeroize` -- plaintext is wiped on drop
- No UI -- pure CLI, composable with any picker via pipes
## Install
```bash
cargo install --path .
```
## Quick Start
```bash
# Start the daemon (foreground)
pbringd
# Or register with launchd for auto-start
cp resources/com.pbring.daemon.plist ~/Library/LaunchAgents/
launchctl load ~/Library/LaunchAgents/com.pbring.daemon.plist
# Pick from history and copy to clipboard
## Commands
### `pbringd`
Daemon binary. Polls `NSPasteboard.general.changeCount` every 500ms, encrypts and stores clipboard content in SQLite.
- PID file: `~/.local/state/pbring/pbringd.pid`
- Handles `SIGTERM` / `SIGINT` for clean shutdown
### `pbring list`
```
<id>\t<timestamp>\t<type>\t<preview>
```
| `--limit N` | Max entries to show (default: 100) |
| `--type text\|image\|file` | Filter by media type |
### `pbring get`
Reads one line from stdin (`<id>\t...`), retrieves and decrypts the entry, and writes raw bytes to stdout. Useful for piping to other tools.
```bash
### `pbring copy`
Reads one line from stdin (`<id>\t...`), retrieves and decrypts the entry, and writes it to the system pasteboard with the correct UTI. Works with text, images, and files.
```bash
### `pbring delete`
Reads one line from stdin and deletes the entry.
```bash
### `pbring clear`
Deletes all entries. DB file remains.
### `pbring wipe`
Deletes all entries, zero-fills the DB file, then removes it.
## Security
### Pasteboard Marker Filtering
The daemon inspects `NSPasteboard.general.types` and skips entries with these markers:
| `org.nspasteboard.ConcealedType` | Passwords (1Password, LastPass, Keychain) |
| `org.nspasteboard.TransientType` | Temporary content (TextExpander) |
| `org.nspasteboard.AutoGeneratedType` | Auto-generated content (Keyboard Maestro) |
| `com.agilebits.onepassword` | 1Password specific |
| `PasswordPboardType` | Legacy password marker |
### Encryption
- Algorithm: AES-256-GCM with random 96-bit nonce per entry
- Key: 256-bit, generated on first run, stored in macOS Keychain (`com.pbring.encryption-key`)
- Keychain access via `security` CLI
### Memory Safety
- Decrypted data held in `Zeroizing<Vec<u8>>` -- wiped on drop
- Encryption key held in `Zeroizing<[u8; 32]>`
## Configuration
`~/.config/pbring/config.toml`
```toml
poll_interval_ms = 500 # Polling interval (ms)
max_entries = 1000 # Max stored entries
ttl_seconds = 86400 # Entry TTL (0 = no expiry)
max_entry_bytes = 10_485_760 # Max entry size (10MB)
record_types = ["text", "image", "file"]
extra_ignored_types = [] # Additional NSPasteboardType strings to ignore
ignored_apps = [] # Bundle IDs to ignore
preview_max_chars = 100 # Preview truncation length
```
All fields are optional; defaults are shown above.
## File Locations
| Database | `~/.local/share/pbring/history.db` |
| Config | `~/.config/pbring/config.toml` |
| PID file | `~/.local/state/pbring/pbringd.pid` |
| launchd plist | `~/Library/LaunchAgents/com.pbring.daemon.plist` |
## Requirements
- macOS 14 (Sonoma) or later
- Rust 1.75+
## License
MIT