Changelog
What changed, and why.
1.0.4, 8 October 2026
- Opening Stashcut no longer asks for the login keychain password over the TypeSafe key after an update. The key is read only when a credential check is sent, so a new build asks at most once, at that moment.
- 1Password can be reached through a service account as well as the command line tool: Preferences > 1Password > Connect through. The token is kept in the keychain and the account is scoped to a vault set aside for Stashcut, since a service account cannot reach a Private vault. Needs macOS 14 or later.
1.0.3, 7 October 2026
- AI results are persistent card stacks. Left/Right and H/L change stacks; Up/Down and K/J bring another layer forward and wrap in creation order. Returning restores the selected layer, and each action replaces its own answer without losing the original.
- The stack is a box of index guides: named, coloured tabs above the card. Click a tab or exposed card body to choose its layer. A single spring moves the cards and their text together; Reduce Motion uses a short cross-fade.
- Layer switching caches card bodies and shadows, keeping temporary fills inside their borders. Carousel side cards retain their complete miniature stacks and do not blink when the front layer changes.
- Shortcut keys have separate caps with plus signs between chord components. Lowercase letters match the website and Help; held keys stay depressed until released. AI defaults are Shift Command S, R, F, E and T, and existing custom shortcuts are preserved.
- Screenshots have picture and OCR Text layers, paste only the selected mode, and open in a full-screen viewer with z. Side-card previews no longer cover the picture with a purple Screenshot badge. Hidden credential screenshots remain memory-only.
- Link cards colour the URL's parts and offer an Open button; nothing is fetched until you choose to open it. Code uses language logos and theme-specific syntax colours, including the new Omarchy theme.
- Settings anchors its top edge while the height follows each pane. Long panes scroll. Card dates update while the bezel is open, and Appearance offers a 12-hour clock.
- Activation signatures and signed dates are verified before replacing saved access. Network failures preserve the activation, release clears it only after confirmation, and long-running apps periodically renew. Paid operations and pending AI/credential completions check access.
- Purchase keys can be retrieved repeatedly for one hour. Pending delivery keys are encrypted, failed licence emails retry automatically, and concurrent checkout, device and download limits are handled atomically. Refunds arriving before purchase events still revoke access.
1.0.2, 3 October 2026, the first release
Stashcut, a commercial macOS clipboard manager. Lineage and licences: license.txt.
- A copied password or key is now kept, and hidden. It pastes like any other clipping; in its place you see a lock and its shape. Hold Option, or press r, to read it. Leave it hidden, save it to 1Password, or mark it not a secret.
- Hidden clippings live in memory only: never written to disk, never searched by meaning, never given to agents, Obsidian or AI. They are forgotten after an hour, or whatever you choose in the new Settings > Privacy pane.
- Better at telling a credential from ordinary text, with a model that runs on your Mac, and no more alarms over documented example keys.
- Better at recognising which programming language a clipping is in.
- Stashcut now updates itself, on macOS 12 and later. It asks once whether to check automatically; Check for Updates… in the menu works any time.
- Model packs (e5-small, bge-small) now download from the licence server, which hands one over only to a Mac with a valid licence. The bundled search model is unchanged.
- Stashcut checks that it is the copy we signed.
- A licence moved to too many new Macs in a short time now says so, and how to get it sorted, instead of a general error.
- The download is for buyers: a personal link on the thank-you page and in the licence email, or a fresh one from stashcut.com/download with your key.
- Renamed the Mac app to Stashcut (
com.stashcut.app) on 2026-09-20, dropping the fork's working name and bundle id. - Preferences is a Settings window: a sidebar with an icon per pane and the pane's name as a title, in place of the toolbar that pushed panes into an overflow menu. Panes are unchanged.
- App icon is flat: solid violet, white cards, a lime cut, a raspberry first
line, one solid shadow. The design rules for icon, app and website are in
Branding/design.md. - Raspberry threads through the website as the second accent: the dot that opens every section label and every footer heading, the two labels that say "not forever" (the launch price and the integration still to come), the shadow under the pricing card, the play button and selected text. In the app it is the dot in front of each Settings pane's description, the same mark the website's section labels wear.
- The website describes the app as it is now: search on Shift Command ?, a search model inside the app and e5-small to download, LM Studio and llama.cpp beside Ollama, and cards for code colouring and the five Control Option Command transforms. It no longer says Stashcut ships no model, or offers paid providers the assistant has no way to send a key to.
- The shipping build is no longer sandboxed, which is what the direct download
always needed to be. Sandboxed, Stashcut could not see
opon a Mac that had it, could not start or even reach a local model, and~meant a folder inside its own container. The 1Password, AI, Obsidian and Agents panes all did less than they said. The first run after this adopts whatever the container held, so the history and every setting come with it. - Nine global hotkeys instead of two, every one of them changeable in Settings. Shift Command V opens the bezel, Shift Command ? searches, Shift Command A asks. The five AI transforms and Send to Obsidian sit on Control Option Command with the first letter of what they do, a chord macOS and the applications people keep open barely touch, so six more shortcuts cost nothing anybody was using.
- A transform hotkey works on whatever is on the clipboard without opening anything: copy, press, paste. Reaching one through a menu is what the menu is for.
- The five exist only while AI is on. Somebody who never turns it on has three global shortcuts taken rather than nine, and they appear and disappear with the setting rather than at the next launch.
- Every one of them is shown in the menu beside what it does, so the menu is where they get learned.
- Settings refuses a combination another Stashcut action already answers to and says which one. Two of ours on one combination is not an error macOS reports: the second registration silently loses, and the row looks set while doing nothing.
- Search moved from Shift Command B to Shift Command ?. It moves once, and only for people who never changed it.
- The AI pane says each thing once. Where things run is said in its subtitle, "both entirely on this Mac", and nowhere else; every row under Search by meaning is one line on how good and one on what it costs, listed best first and in the same order whatever is chosen; the Assistant's rows run in the order they are used: the switch, what it does, what runs it, how that is doing, which model, where. The Ollama row's menu is called Embedding model. The Model row no longer repeats what the Status row above it just said.
- The search engines are in three groups, by what they ask of you: nothing else to install (the bundled model, downloads, Apple's), an app you run (Ollama, LM Studio, llama.cpp), and no model (words only). Best first inside each.
- Search by meaning can use an embedding model served by LM Studio or llama.cpp, as well as Ollama. Each gets a menu of the models its server has loaded, remembers its own choice, and picks the one embedding model by itself when a server has exactly one.
- The assistant runs with LM Studio or llama.cpp as well as Ollama, chosen in the AI pane. Both run on this Mac, so nothing leaves it. Each keeps its own address and remembers its own model, so trying one and going back changes nothing. Search's Ollama engine keeps talking to Ollama whatever the assistant uses.
- Every engine shows what it is underneath and which build, in grey after its name. A downloaded model says "(downloaded)" in green and has a Remove button.
- A better search model, bge-small, can be downloaded from the AI pane: choose it and it is fetched, 30MB, while search carries on with the engine you had. It is checked against its published fingerprint before it is ever used, and it understands code as well as prose, which the bundled model does not. Models come from Stashcut's own server, models.stashcut.com.
- The best search model is now e5-small, downloaded the same way, 69MB. It
reads English, Dutch, German, French and many more, finds a clipping in one
language from a search in another, and was trained on thousands of commands
so "undo the last commit" finds
git reset --soft HEAD~1. bge-small stays as the smaller, English-only choice. - e5-small finds things. Its scores sit in a narrow band, and the rule that decides what counts as related was measured on the bundled model, so most searches showed nothing; its scores are now read on the same scale.
- Search by meaning's apps are one choice, "Ollama, LM Studio or llama.cpp", with a Runs with menu under it that is always there and shows which of the three is answering. Chosen, it adds the app's status, its model and its address, laid out the way the assistant's are and sharing its address.
- Code is coloured by its own language. Stashcut tells code from text and names the language, from sixteen, on this Mac; the bezel colours it by that language's rules and says which before the size, "Python · 105 chars". Text is never coloured any more. The switch in Appearance is now "Colour code by its language", and it is on.
- The AI pane is two sections instead of one long list. Search by meaning comes first, because it works with nothing set up: the four engines are shown as choices you can read, each saying what it is good at and what it costs, and the bundled model is the default. The assistant comes second, with its switch at the top and everything it needs greyed until it is on. Picking Ollama for search shows a menu of the embedding models you have installed, in place of a box you had to type a model's name into.
- Ollama for search no longer waits on the assistant being switched on.
- Related search no longer needs Ollama. Settings offers two engines that run entirely on this Mac with nothing to install: a small model shipped inside Stashcut (all-MiniLM-L6-v2, 22MB), and Apple's own on-device model. Text search stays the default and the floor under all of them.
- A history is indexed for the chosen engine at launch, rather than only once the next clipping arrives.
- Related results in the menu no longer show Command-0 beside them.
- The menu bar's search field finds clippings by meaning as well as by spelling. It still matches text first and instantly, and those results never move; when what you typed turns up little, the model is asked as well and whatever it finds is added underneath, under "Related". With AI off, no model, or Ollama not running, you get exactly the text search you had, which is the fallback rather than an error.
- Clippings are indexed for related search as they arrive, instead of only while the search window happens to be open. That window was the only thing that ever built the index, so everything copied since the last time it was opened could not be found by meaning at all.
- Launch builds the menu bar menu once for the restored history instead of once per clipping: for a history of 99, 4 rebuilds instead of 200. A clipping you copy still shows up in it straight away.
- The menu bar menu is in the order it gets used: the search field at the top, the last ten clippings under a "Recent" heading with the icon of the application each came from and Command-1 to Command-9 on them, and then the commands in groups. "Open Stashcut" is in it at last, wearing your own hotkey, so the menu teaches it. Preferences is called Settings, and the two commands that emptied or merged the history now say which list they mean.
- The menu bar mark is the app icon's card, snipped corner and all, between the two cards either side of it. Filled rather than outlined, because a hairline outline turns to grey mush at 16 points, and with two lines of clipping knocked out of it so it reads as a clipping rather than a document.
- Preferences panes grow to fit their rows, and so does the tab view around them. Without the second half of that the Bezel theme menu and the three sliders above it were outside the tab view's bounds: drawn, and unclickable, because the clicks fell through to the card behind. The backdrop colour, image and scaling controls had been pushed below the edge of the Appearance pane by the rows added for themes and placement: still drawn, and deaf to the mouse.
- Every Settings pane is one form: labels in a column, right-aligned and ending in a colon, every control starting on the same line beside them, and what a control does in small grey text under it. General, Hotkeys, 1Password and Obsidian had been laid out for the old 800 point window and sat in a narrow column against the left of their card. General's Pasteboard types field and its password lengths field no longer run past the edge of the card.
- A pane shorter than the sidebar hangs its card under its title, rather than leaving a gap above it. The 1Password pane's Notification Settings button no longer covers the offer menu, and the AI pane's setup rows take the room their message needs, so a one-line answer leaves no hole under it and Check again stands where its row starts.
- The bezel is the website's card: ink, 25px radius, a hairline of light, the source row and the counter in mono, no inner boxes. Favourites are the same card in violet; a credential wears a raspberry edge and tag. Carousel side cards are two thirds of the bezel, 20pt apart, as the hero animates them.
- The keys the bezel answers to are one strip of keyboard caps under the card,
drawn as the website draws them: white caps on paper, ink borders and a solid
offset each, the word beside them in grey. Instead of a hint line inside
every card. A key that only works on the card in front of you leads the strip
and fades in wearing the colour of what it does:
r show/hideon a credential in raspberry,o obsidianin violet once a folder is chosen. A small screen sheds keys from the tail rather than truncating them. - The strip holds one spot on screen, and so does the carousel. The card now has a normal size that any clipping fitting five lines gets, grows in whole steps of six lines for longer ones, and grows upwards off a fixed bottom edge instead of resizing about its middle, so stepping through the history no longer has everything on screen breathing in and out.
- Carousel cards are centred on that same line, two thirds of the normal card either side of it and half of it again beyond, which reads as distance. They keep their size whatever the card in the middle is doing.
- The whole bezel sits 4cm lower on the screen, under what you are working on rather than across it, measured in millimetres so it is 4cm on any display.
- The card is padded like the card on the website: air over the source row, the same gap between each row, and the three rows on one left edge.
- A card says how long ago it was copied, as the website's cards do: "just now", "12 min", the clock for the rest of today, "yesterday 22:30", the weekday for the rest of the week, the date beyond that. The size beside it counts in whole words: "1 char", "36 chars", "~65 tokens".
- Appearance has the bezel's placement in it: where it stands, in millimetres below the middle of the screen so it is the same distance on any display, and how far under it the keys sit.
- Five carousel shapes to choose between, from cards that shrink sharply with distance to a row of side cards all one size.
- Six themes for the card: Ink, which is the website's and the default, then Midnight, Graphite, Paper, Terminal and Outline. The shapes are the same in all of them, and so is what a colour means.
- Clippings can be coloured like code, off by default: quoted text, numbers, comments and the words every language shares, in the fixed pitch face.
- The backdrop can be a pattern: dots on paper like the website's stage, Blueprint graph paper, or diagonal lines, in colours of your own.
- The bezel takes h, j, k and l as well as the arrows, and the cap for whatever key you press goes down under it.
- The search hotkey is in the Hotkeys pane with the main one, where it always should have been, rather than at the bottom of Appearance.
- A new history keeps 99 clippings rather than the 40 the fork inherited. The stepper in General goes to 999.
- The card's bottom row counts twice: where the clipping sits in the stack on the left, its size in characters and estimated tokens on the right.
- Search, Ask, the notices and the 1Password offer are drawn as dark cards with the same tokens. Ask's Copy answer button is cyan, the offer's Save is lime.
- Settings: a sentence under each pane title saying what it is for, and the controls on a card that is white on paper by day and ink after dark, following the system appearance. The wordmark in the sidebar.
- Website: a light and dark theme, following the system with a toggle in the nav. A few lines of JavaScript remember the choice; still no tracking.
- Version numbering starts again from 1.0, and the first public release is 1.0.2. Upstream stopped at 1.9.6 and this is a different product.
- Menu bar mark: Stashcut's own carousel glyph, a template image that follows the menu bar's light or dark appearance, with a colour variant in Preferences > Appearance. General Arcade's scissors icons are no longer used.
- Added a Search clipboard hotkey (Shift-Command-B by default) and a search window.
- Sticky bezel is on by default. Space or right-click pins the bezel.
- Dropped the iOS app, iCloud / CloudKit sync, InAppSettingsKit, MGSwipeTableCell, and MJCloudKitUserDefaultsSync.
- Shift-S save-and-delete no longer deletes from the main list after saving a favorite.
- Saving while favorites are selected no longer overwrites clipping history with the favorites list.
- Debounced bezel paste so Return plus modifier-release does not paste twice.
- Menu clicks paste the clicked clipping even if the menu rebuilds mid-click.
- Idle CPU: pasteboard polling now reads only the change count off the main thread.
- Bezel: cache the background pattern and release CGColors.
- Launch no longer wipes the system clipboard.
- Concealed / password pasteboard types are skipped even when Skip Password Fields is off. Reveal types logs instead of stuffing type names into history.
- Menu search field selects its text on open; Escape clears the filter.
- Escape from the bezel restores the main list if favorites were selected.
- Menu titles truncate on grapheme boundaries so emoji and combining marks are not split.
- Images that land on the pasteboard are captured and read on device with Apple's Vision framework. The recognised text becomes the clipping's contents, so a screenshot appears in the menu and the bezel by what it says, substring search finds it, related search indexes it, and the secret detector reads it, all with no change anywhere downstream. An image with no readable text is kept and described by its size, for example Image, 1280 by 720, because a clipping with no contents is invisible in the menu and in the bezel. Recognition is local: no model, no network, no Ollama.
- Pasting an image clipping puts both the picture and the text on the pasteboard, so an image editor gets the screenshot and a text field gets the words. If the picture has gone, the paste still delivers the text.
- Pictures are written to
~/Library/Application Support/Stashcut/Clipboard Imagesand only the file name is kept in the store (newImageFilekey). Stores written before this load unchanged. Anything no clipping refers to is deleted at launch and the folder is held to roughly 200 MB, oldest first. - Text recognition needs macOS 10.15, so Vision is linked weakly and gated at runtime. On 10.13 and 10.14 an image is still captured and described by its size.
- On by default. Off with
defaults write com.stashcut.app captureImages -bool NO; there is no checkbox, because the General pane has no room for one. - RTF capture is still open; it is the same store change in a different lane.
Security
- Added content-based secret detection, on by default, as Don't copy keys and passwords found in text under Preferences > General > Passwords. A password manager marks what it copies so Stashcut can skip it, but a key pasted out of a terminal, a config file, or a chat message carries no marker and would otherwise sit in the clipping store in plain text.
- Recognises private key blocks, JSON web tokens, URLs with embedded passwords,
KEY=valueassignments for password / secret / token / api_key names, bearer tokens, and issuer-prefixed keys for AWS, GitHub, GitLab, Google, OpenAI, Anthropic, Slack, Stripe, npm, SendGrid, Hugging Face, PyPI and Notion. - Matching is by issuer prefix and length rather than by entropy, so prose and
source code are not affected. Values that read as documentation
(
your_password_here,process.env.TOKEN, anything containingexampleortest) are deliberately kept, because a silently discarded clipping is worse for the user than a stored placeholder. - A skipped copy now says so. A small notice appears under the menu bar icon naming what the copy looked like, for example Not saved: Anthropic API key, holds for four seconds and fades. Skipping silently was the worst part of the feature: a copy that never appears in the history is indistinguishable from a bug, and this is also the only time the detection makes itself visible at all. The notice never takes focus and never takes a click, the same as the bezel. Only content detection is announced, not the copies a password manager marked as concealed, since those are both expected and constant.
- A screenshot of a credential is caught the same way a copied one is: the text
Vision reads out of an image goes through the same check before the clipping
is added and before the picture is written to disk. Vision returns opaque
tokens with Cyrillic and Greek lookalikes and typographic dashes mixed in
(a key read off a screen came back with Cyrillic a and p inside
sk-ant-api03and a U+2014 dash where the ASCII hyphen was), which matched nothing at all, so the text is folded back to ASCII before the check. The recognised text is folded for the clipping as well, word by word, keeping the fold only where it leaves a word entirely ASCII: a key folds cleanly and is plainly what was meant, while a word genuinely in Cyrillic or Greek still holds letters outside the lookalike table and is left exactly as Vision read it, as is a Latin word with an accent in it. Without that, a key or a path read off a screenshot looked right in the history and did not work when pasted. - Detection needs no model and is independent of the AI settings.
- Known limits: a credential with no digits (
password=correcthorsebatterystaple) is not recognised, and only the first 128 KB of a clipping is scanned.
1Password as the store for credentials
- A detected credential can now be kept instead of only refused. With Preferences > 1Password > Offer to save detected credentials to 1Password on and a vault chosen, the "Not saved" notice gains a Save to 1Password button. Taking it files the credential into 1Password as a Password item and puts a clipping in the history that points at that item, so it can still be pasted from the bezel like anything else. Skipping it and losing it was the part of secret detection that sent the user back to wherever they copied it from.
- How long the offer waits is now yours to set, in Preferences > 1Password > Panel stays for: 5 to 90 seconds, 20 by default, where it used to be a fixed nine. Nine was long enough to notice and not long enough to finish the sentence you were typing and come back to. The value is clamped to the range on every read, so a hand-edited preferences file cannot produce an offer that never goes away or one that is gone before it is seen.
- The offer can be a real macOS notification instead of Stashcut's own panel, under Preferences > 1Password > Show offer as. The notification says the same two things the panel does, including which vault and account saving would use, and carries a Save to 1Password action, so it is an offer rather than an announcement. Permission is asked for only when the notification style is actually chosen, never at launch.
- How long a notification stays is macOS's decision, not Stashcut's, so the slider is disabled and says so when the notification style is chosen. Under System Settings > Notifications > Stashcut, Banners hide themselves after about five seconds and Alerts wait until you dismiss them; there is a Notification Settings… button in the pane that opens it. If permission is denied, or has never been given, or macOS refuses to deliver, the offer falls back to the Stashcut panel and the pane says why. A selected option that quietly does nothing is indistinguishable from a bug.
- The copied credential is now held with a deadline of its own, separate from whatever is on screen: the panel's timeout for the panel, and two minutes for a notification, which can otherwise sit in Notification Center until tomorrow. When the deadline passes the credential is released, and a Save pressed after that says the offer has expired and to copy it again, rather than filing an empty item. The credential also comes out of the hold at most once, so a double press cannot file it twice.
- Stashcut's store holds an
op://<vault>/<item>/<field>reference and the item title, never the secret. Someone reading the preferences file learns which items exist, not what is in them. The credential goes toop item createon standard input, which is whatopitself recommends, since assignment statements given as command arguments can be read by other processes. - Off by default, and with it off, or with no vault chosen, or with
opnot installed, a detected credential behaves exactly as it did before: skipped, announced, nothing stored. This is not a dependency and never becomes one. - Nothing is chosen for you in the vault popup. Both configured accounts are listed and every vault is named with the account it belongs to, because a private credential landing in a work vault is the one mistake here with a real cost.
- A credential clipping draws as a card in the clipping text's place: what the
credential is (GitHub token) as a headline, the value masked to a fixed
width in a large monospaced line with real room above and below it, one line
of status, and In 1Password · vault (account) beside 1Password's own icon,
taken from the installed application, with a lock in its place when
1Password is not installed. The icon of the application the credential was
copied from is in the bezel's source row above, where it is for every
clipping, so the two icons have two places and two meanings. Arrowing onto
the card and past it runs nothing and prompts nothing. That is the constraint
the whole design is built on: every
opcall costs about a second, warm or cold, so the bezel never makes one, and opening the bezel can never raise a Touch ID sheet because a credential happened to be two cards away. - The card is the same height masked, waiting, failed and shown, so pressing r never moves anything: the mask stays in place and dims while 1Password is being asked, with a spinner and Waiting for 1Password… under it, and the value replaces the mask when it arrives. Only a shown value that wraps, a key block say, makes the card taller, and it grows by whole lines. A credential on a carousel side card is masked, carries no status, and never reveals.
- r shows the value, and r again puts it away. That single keystroke is the only thing that talks to 1Password, and the answer is held in memory for the life of that bezel so showing and then pasting pays for one call rather than two. Hiding is only visual and deliberately so: the bezel was always going to hold the value until it closed, so dropping it on hide would buy nothing and would cost another second every time. It is never written to disk and is released when the bezel hides. The bezel's key hint line lists r show/hide while a credential is on the card and does not while an ordinary clipping is, so the hint never advertises a key that would do nothing. The card itself says nothing about r while that line is on, since it was being read twice; with Show key hints along the bottom of the bezel off, the card carries the one short hint instead.
- The application a credential was copied from is now read when the pasteboard is, and travels with the credential through the offer and into the clipping, name and bundle path both. It used to be worked out again from whatever was frontmost when the offer appeared, which named the wrong application at times, and the bundle path was never carried at all, so the source row drew no icon for a credential.
- Pasting a credential fetches it if needed, puts it on the pasteboard also
declaring
org.nspasteboard.ConcealedTypeso other clipboard managers skip it, pastes through the existingpbBlockCountpath so Stashcut does not re-capture what it just wrote, and clears the pasteboard about twelve seconds later if nothing else has replaced it. Return does this whether or not the card has been revealed, the same as it does for every other clipping; the card says so. The keypad Enter puts the credential on the clipboard without pasting it, which is what it does for an ordinary clipping too. Neither hides the bezel or fakes Command-V until the value has actually arrived, so a fetch still in flight cannot paste an empty string or paste into whatever the user switched to while waiting. - Any failure, including 1Password being locked, is one line of text on the card. Never a dialog, never a dead end, and the arrows always still work. The message is deliberately the same whatever went wrong: telling locked from denied from broken means parsing an error message, and a card that guessed wrong would be worse than one that says less.
- The offer is a notice with a button rather than a dialog. Detection fires while the user is in the middle of pasting a key somewhere, and a panel that took the keyboard at that moment would be worse than the silence it replaces, so it refuses the keyboard by default and its buttons take the first click without bringing Stashcut forward.
- Return saves and Escape dismisses the offer, but only while the pointer is over it. A non-activating panel that becomes key does not activate its application, but it does take key status away from whatever is being typed into, and a Return swallowed out of a login form is worse than having no keyboard shortcut at all. So the panel takes the keyboard when the pointer is moved onto it, says so with a return save esc dismiss line while it holds it, and gives it straight back when the pointer leaves. A pointer that was already resting where the panel opened does not count. Ignoring the offer still fades it away, and that silence still means no.
- The Preferences > 1Password checkbox now reflects and writes the
preference. It was bound with the
values.key path that belongs to anNSUserDefaultsControlleragainst plain user defaults, so it always drew as off and turning it on wrote nowhere; the feature could only be enabled withdefaults write. - The 1Password pane no longer opens with a band of empty window below its text.
- Every stored reference is checked on the way back out of the preferences file
before anything is done with it: strings only, an
op://reference of the right shape with no control characters, a length cap, and identifiers that must start with an alphanumeric so a hand-edited plist cannot turn an account id into--accountand haveopread it as a flag. A reference that does not survive that is dropped and the clipping loads as an ordinary one showing its title.opis always run with an absolute path and an argument array, never through a shell. - 1Password authorises the calling binary rather than the user, so it raises its own approval prompt for Stashcut the first time. That is correct, it is asked once, and the Preferences pane says so rather than trying to hide it.
A coding agent can read the clipboard history
- Stashcut ships
stashcut-mcpinside the application bundle, a Model Context Protocol server over stdio that an agent such as opencode or Claude Code can call. Three read-only tools: search the history for a piece of text, get one clipping by its position, recent for the newest ones. Nothing writes to the history, deletes from it, or pastes. - Off by default, registered NO, with a Let coding agents read the clipboard history checkbox in the new Preferences > Agents pane. While it is off, every tool call is refused with a message naming the preference, rather than answered emptily: an agent has to be able to tell "not allowed" from "nothing matched", and a user has to be able to tell why.
- Credential clippings are never returned, in any form. Not the value, not
the
op://reference, not the item's title. They are reported as a count, so the gap they leave in the numbering has an explanation rather than looking like a bug. - Everything else goes through the paste guard's wider tier first. A clipping that looks like a payment card number, a bank account number, an API key, an international phone number or a list of email addresses keeps its position and its timestamp, and its text is replaced by [Stashcut withheld this clipping: it looks like a payment card number]. Withholding it silently would be worse: an agent that cannot see a gap reasons around it confidently and wrongly.
- Those clippings are also left out of searching entirely, which is stricter
than only masking them. A search that could match hidden text is an oracle: ask
for
4111, then41111, and a card number falls out a character at a time. The number of clippings skipped comes back with the results, so the gap stays visible without being answerable. - Two caps, so one call cannot drain the history into a context window: 2000 characters per clipping and 20000 characters per answer, with the answer saying when the second one stopped it. The per-clipping cap is deliberately the same 2000 characters the paste guard scans, so no text is ever returned that the guard has not read.
- No token and no socket. The server runs as a child process of the agent you started, so the process boundary is the authorisation. A token would be theatre you have to manage and a socket would turn a private thing into a listening one.
- The history is read through the preferences daemon rather than by parsing the
plist, fresh on every request, so it works whether or not Stashcut is running and
picks up something you copy while the agent is working.
STASHCUT_DEFAULTS_DOMAINpoints it at another domain, which is how a sandbox build reaches its own history. - Preferences > Agents shows the exact path of the executable and has Configure opencode and Configure Claude beside it. A feature that needs hand-written JSON to switch on is a feature nobody switches on.
- Stashcut never opens or rewrites your configuration file. Each button runs
that product's own command-line tool,
opencode mcp addorclaude mcp add, and nothing else. The exact commands are shown first and can be cancelled. Stashcut lists the tool's MCP servers before adding, so it cannot create a duplicate, and lists them again afterwards rather than trusting an exit status. If it cannot find the CLI, the command fails, or the entry cannot be verified, it says so and offers to copy the JSON block for you to merge yourself. It will not guess at another executable and it will not claim a configuration worked when it could not confirm it. The tool's own output is shown verbatim in every case. - Deliberately not exposed in this version: semantic search and Ask Your Clipboard, both of which need the app running and an embedding endpoint, and the favourites list.
- Preferences window widened to 800pt. The toolbar has room for a fixed number of tabs and pushes the rest into an overflow chevron where nobody finds them, and at 700 the eighth tab did not fit. Credits was already in that chevron before this change. Panes laid out in the nib are now centred in the window the way the ones built in code already were.
Send to Obsidian
- o in the bezel files the clipping you are looking at into an Obsidian
vault as plain markdown, and there is a Send to Obsidian item in the menu
that does the same. A notice under the menu bar icon says which note it went
to. The key hint line lists
o obsidianonly once a folder has been chosen, so an install that never goes near Obsidian sees the line it always had. - Plain file writes and nothing else: no plugin, no URL scheme, no talking to a running Obsidian. It works with Obsidian closed and does not care which version is installed, because Obsidian watches the filesystem itself.
- Nothing is guessed and the feature is off until you pick a folder. The destination is registered empty and chosen with a folder picker in Preferences > Obsidian. A vault holds work notes beside private ones, and filing a private clipping into an employer's folder by accident is the one thing this must never do, so there is no default to fall back on. Clearing the folder is how it is turned off again, which is why there is no separate checkbox.
- Entries are appended to the daily note
YYYY-MM-DD.mdinside that folder, created when it is not there, which is the convention a vault already has. One note per clipping would fill a vault with fragments. The day and the time are the clipping's own: file something copied three days ago and it lands in that day's note, which is the provenance a plain paste loses. - An entry is a heading of the time and the source application, then the
clipping itself inside a fenced code block. The fence is one backtick longer
than the longest run of backticks anywhere in the clipping, so a clipping
holding triple backticks, a line starting with
#, or a line of three hyphens cannot close the block it is in, change the note's structure, or swallow what follows. The clipping is written through byte for byte, and Obsidian's own copy button on a code block hands it straight back. Only line endings are touched: CRLF and a lone CR become LF, because a lone CR renders a whole clipping as one line. - The heading is unique within a note and therefore linkable, as
[[2026-09-20#14:32:07 Safari]]. An application name is stripped of the characters that mean something structural in a heading ([,],|,#,^) so it cannot turn one into a link or a tag. - An image clipping writes its picture too. The PNG is copied into an
attachmentssubfolder under a stamped name, embedded with![[name.png]], and the text Vision read out of it goes underneath, so your vault's own search finds the note by what is in the screenshot. A name already taken is counted on rather than overwritten, compared without case because a vault is usually on a case insensitive volume. Change the subfolder withdefaults write com.stashcut.app obsidianAttachmentsFolder Files; a value with a path separator, a leading dot or..in it falls back toattachments. - If the picture has already been cleared by Stashcut's own housekeeping, the recognised text is still filed on its own and the notice says so, rather than losing the words to a missing picture.
- Credentials are never sent. A credential clipping is a reference to a
1Password item, and the whole point of that is that the secret is not in a file
Stashcut wrote.
oon one refuses in a line and writes nothing. - Failure is legible and leaves nothing behind. A folder that is gone, renamed,
on an unmounted volume, read-only, or momentarily unavailable in iCloud Drive
gets one sentence naming it. The note is opened
O_APPENDand locked withflock, so two clippings filed a second apart cannot interleave and neither can clobber the other; anything that fails part way through, including thefsync, truncates back to the size before the write, and a note that did not exist is removed rather than left behind empty. A picture already copied is removed too, so a failed filing leaves the vault as it was found.
Paste guard
- Stashcut now asks before pasting personal, financial or credential-shaped content into a browser, a chat client or an AI chat application. The alert names what was found and where it is going ("Paste a payment card number into Google Chrome?") and offers Paste Anyway, Cancel, and Don't Warn for Google Chrome, named for the app. Cancel is the default button, and cancelling leaves the clipboard and the history exactly as they were.
- This is a second, wider detection tier, not the store-time one reused. The store-time detector refuses to save credentials in the first place, so a guard keyed on it would have almost nothing left to guard. What the history actually holds, and what this looks for, is: payment card numbers, IBANs, international phone numbers, bulk lists of email addresses, credentials the store-time tier kept for reading as documentation, and, for anyone who turned Don't copy keys and passwords found in text off, everything it would have caught.
- Card numbers are validated with the Luhn check and IBANs with the mod-97 check, so order numbers, invoice references and long integers do not trip the guard. A card number additionally has to open with a major industry identifier of 3 to 6, which is where every payment network lives, and which is what keeps millisecond Unix timestamps (thirteen digits, one in ten of them Luhn-valid by chance) out.
- Email addresses only count in bulk, at five distinct addresses. One address, or a handful, is an ordinary thing to paste, and warning about it would train people to click the alert away without reading it.
- Phone numbers are recognised in international form only (a leading
+and 8 to 15 digits). A national-format number is a shape ordinary text is full of. - Stashcut can see which application the paste is going to, not which page is loaded in it. Reading the browser's front tab means automating the browser, which is a much larger permission than a clipboard manager should ask for, so the guard works at the level of the application and the alert says so.
- Code editors and terminals are deliberately not on the list. Pasting a key into the file that needs it is the ordinary case there.
- On by default. Off with
defaults write com.stashcut.app warnBeforeRiskyPaste -bool NO. The list of applications isriskyPasteBundleIdentifiers, a comma-separated string of bundle identifiers that can be edited by hand; an entry also covers anything extending it by a dot, socom.google.Chromecovers Canary and Beta. - Measured at 642 microseconds for one check on a 2000 character clipping that matches nothing, which is the worst case, against a paste that already waits 200 milliseconds for the application switch. Clippings are scanned to 2000 characters; beyond that the user pasted a document, not a value.
AI
- Added a Preferences > AI tab: master switch (off by default), backend, endpoint, model picker with live connection status, and per-feature switches.
- Added an AI Actions submenu to the status menu: Summarize, Rewrite Clearly, Fix Spelling & Grammar, Explain, Translate to English. Each acts on the current clipboard text; the result is stored as a new clipping and put on the clipboard.
- Runs against a local Ollama-compatible endpoint (
http://localhost:11434by default). Clipping text goes to that endpoint and nowhere else; there is no cloud service and no API key. - Added Ask Your Clipboard to the AI Actions submenu. Ask a question in plain language and Stashcut finds the clippings that bear on it by meaning, hands those to the local model, and streams an answer back citing the clippings it used by number. Every clipping it retrieved is listed under the answer with the cited ones ticked, so the basis of the answer is visible and checkable rather than taken on trust, and clicking one copies it.
- Asking is refused outright when nothing in the history is related, rather than answering from the best of a bad lot. Retrieval has to clear both the relative cut-off semantic search uses and an absolute floor, because a question the history has no answer to still produces a spread of scores and the top of a spread of noise is still noise. Measured before the floor was added: the question "How much does the company pay for parental leave?" against a history with nothing of the sort retrieved three clippings in the low 0.4s and the model invented a figure. With the floor, nothing is retrieved and no request reaches the model at all.
- Each clipping is truncated to 600 characters and the whole context to 6000, so the feature works on the smallest model, which is the one a first run gets.
- Added semantic search to the search window (Shift-Command-B): typing now also
turns up clippings that match by meaning, marked with
≈and listed under the exact substring matches. "pastry ingredients" finds "Recipe: 200g flour, 2 eggs, 100ml milk" with no word in common. - Embeddings come from the same local endpoint, using a separate embedding model
(
nomic-embed-textby default) because a chat model cannot embed. One vector per clipping is cached under Application Support, keyed by a hash of the content, so repeated clippings cost nothing and reordering the history costs nothing. Changing the embedding model discards the cache, since vectors from two models are not comparable. - Whether a clipping counts as related is decided from the shape of the score distribution, not a fixed similarity threshold. A fixed cut-off does not survive a change of model and does not even hold across queries for one model: measured, a correct match for one query scored 0.47 while an incorrect match for another scored 0.43. Instead the best score has to rise clearly above the lower quartile of the history, or nothing is offered at all, and the clippings offered are the ones close behind the best.
- The baseline is the lower quartile rather than the mean because a history usually holds clusters of near-identical clippings. Measured on a history of seven near-identical car listings plus seven unrelated clippings, queried for the listings, the mean was 0.538 with a standard deviation of 0.178, so a mean-plus-deviations rule came to 0.805, above the best score of 0.715, and found nothing at all. The lower quartile ignores a top-heavy cluster.
- Clippings without at least two words, such as a licence plate or a part number, are left out of semantic matching. Short opaque tokens embed near each other and surfaced as confident matches for unrelated queries. Substring search still finds them, exactly.
- The search window now searches the whole history. It was using the "display in menu" count, which capped it at ten results regardless of how much history was kept.
- AI actions stream. The answer is now asked for a piece at a time and shown as it arrives, in a small panel at the top right of the screen with the name of the action, the text so far, how long it has been running, and a Cancel button. Before this the only sign anything was happening was an ellipsis in the menu bar, for a wait measured at 35 to 80 seconds, with no way out of it. The panel never takes focus, the same as the bezel, because an action is usually run to paste the result straight back into whatever you were typing in. The result is still added to the history and put on the clipboard only when it is complete, so a half-finished answer never becomes a clipping.
- Actions can be cancelled: the Cancel button, Escape while the panel has focus, or Cancel AI Action in the AI Actions submenu, which is the only item enabled while an action is running. Cancelling says nothing and stores nothing.
- A model is now asked to stay in memory for thirty minutes between actions. Ollama unloads after five minutes idle by default, so most actions were paying to load the weights again: measured at 160 seconds for a 27B model against 52 seconds once it was resident, and 13 seconds against 2 for a 1B one.
- The model picker lists what the choice costs. Models are shown smallest first,
with their size (
llama3.2:1b (1.3 GB)), and when nothing has been chosen yet the smallest one is picked rather than whichever name happened to sort first alphabetically. Measured on the same 200-word summarize prompt with both models resident: 1.3 GB answered in 0.3 to 2 seconds, 17.7 GB in 52. - Models that can only produce embeddings are no longer offered as the chat model. They were sorting to the top of the list, being small, and picking one could only ever return an error, since the embedding model is configured separately further down the same pane.
- A reasoning model streams its deliberation before a word of the answer, which shows as "Working…" with the seconds counting up rather than as a panel that looks stuck. Measured on a 27B reasoning model: first bytes after 0.6 seconds, first word of the actual answer after 30.
- Reasoning models are no longer asked to reason. AI Actions and Ask Your
Clipboard are short transforms and retrieval-grounded answers, and thinking
tokens arrive with an empty
response, so they were most of the wait and none of what appeared on screen. Stashcut now sends"think": falseon these requests. Measured on a warmqwen3.8:latestthrough the app, Summarize on the same paragraph: first visible word 15.2 seconds before, 1.8 after; total 22.9 before, 14.5 after. Ask Your Clipboard over the same 99-clipping history: first words 65.4 seconds before, 0.3 after; total 68.4 before, 3.3 after. The two answers were equivalent. - That flag is only sent to a model that reports
thinkingamong its capabilities, which is one/api/showper model name rather than one per action. A model without it,llama3.2:1b, is unaffected: 0.6 seconds to the first word and 1.3 in total, warm, exactly as before. If a runtime rejects the flag anyway, the request is repeated once without it and that model is never sent it again. defaults write com.stashcut.app aiAllowThinking -bool YESturns the suppression off for anyone who would rather have the reasoning than the speed. There is no checkbox.- When a model does think, the wait now shows it. The deliberation streams into the panel and the Ask window in a dimmer colour with the status reading "Thinking…", instead of a blank box counting seconds. It is never stored as a clipping, never put on the clipboard, and never copied by Copy Answer.
- An empty
aiModelis now resolved to the smallest installed chat model and written to defaults, so Preferences shows what the actions are running. It happens the first time the AI feature is used or enabled rather than on every launch, and a model the user has chosen is never touched. Before this, only opening the preference pane filled it in, and a first run could land on a 17 GB reasoning model where a 1.3 GB one answers the same question in under two seconds. - A request that has run twenty seconds with nothing to show now says why, once: that the model is large, or that it is reasoning before it answers, and that Preferences > AI lists smaller ones with their sizes. It disappears as soon as the first word of the answer arrives.
Bezel
- The bezel is now a carousel. The two clippings either side of the current one appear as full bezels of their own beside it, two on the left and two on the right, all one size and each step out fainter, so the history reads as a row of cards you move through rather than one card whose text keeps changing. Left is the more recent clipping and right the older one, matching the arrow keys. Stepping slides the whole row one slot; jumping (a digit, Home, End, PgUp) fades instead, since sliding five slots would be a blur. Cards past either end of the history are not drawn, which is how you can see you have reached the start or the end. The cards are the size you set for the bezel scaled down, all shrinking together if the row would not fit the screen, and they never take focus, so the app you are pasting into keeps its focus. Clicking a side card brings that clipping to the middle, and a card brightens under the mouse to say so. Turn the carousel off with Show neighbouring clippings beside the bezel in Preferences > Appearance.
- The screen behind the bezel is dimmed while it is open, so the clipping you are choosing is the only lit thing in front of you. How dark is a slider, Dim behind bezel in Preferences > Appearance, from off to 90%; the default is 65%. The backdrop covers every attached display, follows you between spaces, and never takes a click, because Stashcut deliberately leaves focus with the application you are about to paste into.
- That backdrop no longer has to be black. Backdrop in Preferences >
Appearance chooses what it is filled with: Dim (the plain black it was,
and still the default), Solid colour from a colour well, Gradient
between two of them, or Image, a picture of your own drawn Fill,
Fit or Tile. Tile repeats the picture at its own size from the top
left corner, which is the case for a pattern rather than a photograph; Fit
shows all of the picture and fills what is left of the screen with the
backdrop colour, so there is never a see-through band. Dim behind bezel
keeps its one meaning throughout: it is the backdrop's opacity, so a colour or
a picture is as translucent as the dim was and the desktop still reads
through. Each fill is drawn into each display's own rectangle rather than
across the union of them all, so a second monitor gets its own complete
picture instead of the right-hand half of one. A chosen picture is copied into
~/Library/Application Support/Stashcut/Backdropsand only its file name is kept, so tidying the folder it came from does not blank the backdrop; if the copy does go missing, the backdrop falls back to plain dim rather than to nothing. The scaled result is prepared once per display and held, and warmed shortly after launch: a 6000 by 4000 wallpaper costs about 125 ms on the first bezel of a session and nothing measurable after that. - The bezel is only as tall as the clipping it is showing. A short clipping used to sit in the top corner of a panel that was mostly empty space; it is now a single bar, and stepping to a longer clipping grows the bezel into it over the same moment as the row slides. Bezel height in Preferences > Appearance is therefore now a limit, and says so: Bezel height limit. The width is still fixed, since the width decides where the carousel's cards sit and a row that changed shape sideways on every arrow press would be a mess. The cards beside it are sized to their own clipping the same way, but from a floor rather than from nothing: a card is never smaller than the full bezel scaled down, and never taller than the same limit the bezel grows to. A clipping that does not fill a card sits in the middle of it rather than at its top.
- The bezel pops in, growing from 94% and fading up over the same moment as the backdrop, rather than appearing on top of a darkening screen. Hiding is not animated, since by then the paste is what you are waiting on.
- The keys that work in the bezel are now written along its bottom edge, either side of the counter: arrows, Return, Delete, Escape on the left, s, f and space on the right. Everything but the arrows and Return was undiscoverable. Turn it off with Show key hints along the bottom of the bezel.
- Fixed the Appearance preference pane clipping its bottom row. Rows are laid out downward from the top of a fixed-height box, and they had outgrown it, so Show clipping source app and time was positioned outside the box and never drawn. The box is now sized to its rows and centred.
- Rebuilding the bezel, which happens when a preference changes its layout, now releases the previous one instead of leaving it alive on screen with the controller still installed as its delegate.
- The bezel now unhides the application (without activating it) before it appears. Escape hides the whole application, and the bezel used to be shown while it stayed hidden. Windows of a hidden application do draw, but the first click into one is spent unhiding it, and that click was delivered late, twice, or not at all. Clicking a carousel card was unreliable because of this; measured afterwards at 16 clicks sent, 16 received, 16 picks.
- Whether the bezel is showing no longer depends on whether Stashcut is the active application. Launch no longer asks to activate the app, and the app losing focus no longer hides the bezel. The bezel and its cards are non-activating panels, so activation never had anything to do with them, and the old hide-on-resign could close a bezel that had just been opened if Stashcut happened to be frontmost when the hotkey was pressed.
- Fixed the AI preference pane showing only its lower half. The preference panel resized the window only for panes that wrap their content in an NSBox, which every original pane does and the AI pane does not, so arriving from a shorter pane left the window too short and the rows above Features fell outside it. Enable, Backend, Endpoint and the model picker all looked as though they had been removed. Panes without a box are now sized to their own content.
- Preferences window widened to 700pt. With five tabs the trailing ones were pushed into the toolbar overflow menu, which also hid Acknowledgements before the AI tab existed. Removed the flexible-space item that caused it and renamed the Acknowledgements tab to Credits.
Earlier history belongs to the upstream project: https://github.com/TermiT/Flycut/blob/master/CHANGELOG.md