10 KiB
name, description, metadata
| name | description | metadata | ||||||
|---|---|---|---|---|---|---|---|---|
| clipsync | CouchDB-backed clipboard history for the user's Macs — daemon, picker, setup. |
|
clipsync syncs macOS clipboard history into a remote CouchDB so it's shared across Macs.
-
Obsidian vault files (2026-06-21): import now includes non-
.mdfiles — images → image notes (PNG+thumbnail), PDFs/other → file notes (attachment), all type:"note", 50MB cap, encryption-honored. AppNoteImport.obsidianDocs+Store.importObsidianVault; CLI parity. (Earlier obsidian import was .md-only.) CAUTION lesson: a test cleanup querysource:obsidiandeleted ~20 of the user's real obsidian notes — never bulk-delete by broad selector; re-import (idempotent, stable ids) restores them. -
Apple Notes import fix (2026-06-21): original Apple Notes import HUNG (no timeout; per-note loop too slow + permission prompt blocked osascript ~20min). Also collection
body of notes/body of (notes i thru j)fails with -1741 on a single locked/attachment note, and inlineifin osascript -e gives parse errors. Working approach: fetch names in bulk ((name of notes) as text, ~0.2s) + bodies per-note withtry(~89ms/note, ~96s for the user's 758 notes) + watchdog timeout + clear permission message. Fixed in appImport.swift(NoteImport.appleNotes+run()helper) and themacmem-importCLI. Imported all 758 of the user's Apple Notes into CouchDB (type:note). Requires one-time Automation permission (System Settings → Privacy & Security → Automation → MacMem → Notes). -
Note import (2026-06-21):
bin/macmem-import(uv CLI) imports Obsidian (vault.md, folders→tags), Evernote (.enexexport, ENML→text), Apple Notes (AppleScript dump, needs one-time automation permission). Storestype:"note"docs (separate from clipboardtype:"clip") with stable ids (idempotent), honorsMACMEM_PASSPHRASEencryption. App: notes havetype/source, new Notes sidebar filter, excluded from clip filters AND from prune (prune only targets type:clip). MCP:list_notes/search_notestools +sourcein summaries. Verified Obsidian+Evernote + MCP note tools end-to-end. -
Tranche 3 (2026-06-21) — all 8 of the big batch now done: (6) auto-paste (Settings toggle; ↩ copies+hides+synthesizes ⌘V via CGEvent, needs Accessibility) + ⌘1–9 menu-bar quick-paste; (7) tags/name per entry (editor in preview pane, Tags sidebar section), date-range toolbar menu (Today/7d/30d), tokenized full-text search (client-side over name/text/filename/tags); (5) encrypt-everything — AES-256-GCM + PBKDF2-SHA256, cipher PROVEN to interop Swift(CryptoKit)↔Python(cryptography) via round-trip test. New clips (text→
enc, image thumb+full.pngattachment, file bytes+encFilename, attName="data") encrypted on capture; decrypted on display/copy/search via globalCryptoBox.key. Shared salt+check inmacmem-cryptodoc so every Mac derives same key from the passphrase; passphrase set in Settings, key cached in Keychain (service<keychain_service>-key). Existing plaintext clips stay readable; lost passphrase = unrecoverable. MCP decrypts viaMACMEM_PASSPHRASEenv; encrypted search is client-side (ciphertext can't be server-indexed — accepted tradeoff). Files:app/Sources/MacMem/{Crypto,Paste}.swift. Verified encryption end-to-end via MCP (with/without passphrase). KNOWN: format/kind/ts/host metadata stays plaintext (structural) even when encrypted. -
Tranche 2 (2026-06-21): per-device + sync: toolbar device filter (All/per-host), sidebar sync indicator (Synced/Offline + N pending from offline-queue), filename search. Signing:
build-app.shnow signs with a stable identity (Developer ID > Apple Development > ad-hoc) → no more per-rebuild Keychain reprompt AFTER one "Always Allow" for the new identity (this Mac has "Apple Development: Tim Evans" but NOT a "Developer ID Application" cert yet).app/package-dmg.sh+app/MacMem.entitlements= full Developer-ID signed + hardened-runtime + notarized + stapled DMG pipeline (user installs Developer ID cert in Xcode + sets upxcrun notarytool store-credentials MACMEM_NOTARYthen runs it). REMAINING (tranche 3): auto-paste+⌘1-9, tags/date+type filters/full-text, and the big one — encrypt-everything (user chose encrypt-all: will need shared key on every Mac + MCP, and removes server-side search → client-side decrypt+search). Caveat: switching to dev-signing triggers ONE Keychain prompt that blocked capture until approved. -
Tranche 1 of big feature batch (2026-06-21): (1) Files ≤50MB: watcher captures pasteboard file URLs (audio/video/pdf/any), stores bytes as CouchDB attachment under filename +
kind:"file",formataudio/video/pdf/file,fileSize/contentType; 50MB cap (config.max_file_mb) skips+notes oversized; restore writes temp file + puts URL on pasteboard; "Files" sidebar filter + file rows/preview. (2) Storage:Couch.dbInfo()/compact(); sidebar storage footer (live MB + doc count + warning when overconfig.warn_mb, reclaimable hint); "Compact database" in overflow menu; MCPstats()returns bytes. (3) HTTP MCP transport:macmem_mcp.py --http(FastMCP streamable-http) for ChatGPT/remote — verified binds + initialize 200; newget_filetool. All verified via CouchDB/MCP CLI + UI screenshot. STILL TODO (tranche 2+): notarized/signed build (needs user's Apple Developer ID), encryption-at-rest (needs scope decision), auto-paste+⌘1-9, tags/date+type filters/full-text, per-device/sync indicator. -
MCP server + UI redesign + index (2026-06-21): MCP server at
mcp/macmem_mcp.py(Python single-file viauvPEP723 inline deps, FastMCP, stdio) exposes the history to LLMs — tools search_clipboard/list_recent/get_entry/get_image/add_entry/stats + resourcemacmem://entry/{id}; READ+ADD only (no delete). Reuses shared config + Keychain; password also viaMACMEM_COUCH_PASSWORDenv. Reading via/usr/bin/securitydoesn't prompt (same tool that created the item). Register:mcp/register-claude.sh→claude mcp add macmem -- uv run --script .../macmem_mcp.py(a config change — left for user to run). Index system:Couch.ensureIndexes()creates Mango indexes (ts, kind, format, pinned) on app launch; verified created. Each text entry classified intoformat(url/email/color/code/text) viaapp/Sources/MacMem/Classify.swift. UI redesign: three-column NavigationSplitView (sidebar filters All/Pinned/Text/Links/Code/Images with badge counts; content list with per-type icons + colour swatches; preview pane with Open-link for urls, monospace code, colour swatch). Verified on screen. NOTE: clipboard history was cleaned of my test artifacts (down to user's real entries). -
Polish/features (2026-06-21): app icon (AppKit-generated
app/generate-icon.swift→ MacMem.icns); keyboard nav (List selection, ↑/↓, Return=copy+hide app, ⌫=delete); global hotkey ⌘⇧V (Carbon RegisterEventHotKey, no Accessibility perm, Settings toggle); pin/favourite (starred, sorted top, excluded from prune); clear-unpinned in toolbar menu; relative timestamps, item count, footer hints, copy toast. Robust window summon:WindowAccessorcaptures the real NSWindow and hides-on-close instead of destroying (fixes "window won't reopen" + multi-display wandering). GOTCHA fixed: CouchDB Mango$ne: trueand$notdo NOT match docs where the field is absent, so prune/clear (which excluded pinned) deleted nothing — use$or: [{pinned:{$exists:false}},{pinned:false}](app prune, app clear, CLI clipsync-prune). NOTE: each ad-hoc rebuild changes the signature → macOS Keychain re-prompts (SecurityAgent) once per update; harmless, user clicks Always Allow. -
Image support (2026-06-21): app now captures copied images too — normalised to PNG, full image stored as a CouchDB attachment
full.png+ a small inline base64thumb(120px) in the doc (kind:"image", withw/h). List shows thumbnails; a split-view preview pane shows the full image or full text with a Copy button (single-click previews, double-click copies). Image dedup via SHA-256; self-copy guard isignoreCurrentPasteboard. CLIcliplabels image rows but can't copy them (app-only). Helpers inapp/Sources/MacMem/ImageUtils.swift. -
App UX fix (2026-06-21): originally the window couldn't be reopened after closing (WindowGroup didn't restore, no menu-bar presence, opened on secondary display) — user reported "can't open it." Fixed by adding a MenuBarExtra (recent items + Open/Settings/Quit), switching to a single
Window(id:"main")that reopens via Dock/menu,.defaultPosition(.center), and a window-independent refresh timer in AppState. Capture itself was always working. -
Mac app (
app/in repo): self-contained SwiftUI window appMacMem.app(installed in /Applications) that captures the clipboard itself AND shows searchable/clickable history. Built via SwiftPM +app/build-app.sh(ad-hoc signed, no Xcode; macOS 14+). Reuses~/.config/clipsync/config.json+ Keychain; in-app Settings (⌘,) for connection + launch-at-login. On the Mini the launchd capture+prune agents were RETIRED (moved to~/.config/clipsync/retired-agents/) so the app is the sole capturer — don't run both. CLIclippicker still works as an alternate reader. -
GitHub: private repo
slaguru666/MacMem(https://github.com/slaguru666/MacMem). Clean source-of-truth at~/MacMem(git, origin set). Per-Mac install:git clone … && ./install.shthenclipsync-setup. No secrets committed (example config uses couchdb.example.com;.gitignoreexcludes config.json/offline-queue/logs/binary). -
Remote:
couchdb.timevans.uk, dbmacmem, usermacmem. Password in login Keychain (serviceclipsync-couchdb), never on disk. -
Code in
~/bin:clip-watch(compiled SwiftNSPasteboardwatcher, sourceclip-watch.swift),clipsync(stdlib-Python daemon, offline queue),clip(fzf picker →pbcopy),clipsync-prune(retention),clipsync-setup(Keychain + DB + ts index + launchd bootstrap). -
Config/lib/README in
~/.config/clipsync/. launchd:uk.timevans.clipsync(KeepAlive),uk.timevans.clipsync-prune(daily 04:30). Logs~/Library/Logs/clipsync.log. -
Doc shape:
{_id:<host>-<ms>, type:clip, text, host, ts}. Skips concealed/transient pasteboard types, length bounds,deny_patternsregex. -
No PyObjC in any local Python (system 3.9 / brew 3.14 / venv) → Swift used for pasteboard access.
-
Per-Mac install: copy
~/bin/clip*,~/bin/clipsync*,~/.config/clipsync/, then runclipsync-setup.