MCPcopy Index your code
hub / github.com/NotAShelf/stash

github.com/NotAShelf/stash @v0.3.6

Chat with this repo
repository ↗ · DeepWiki ↗ · release v0.3.6 ↗ · + Follow
173 symbols 336 edges 17 files 47 documented · 27%
What it actually does AI analysis from the code graph — generated when you open this
loading…
README

Stash

<a alt="CI Status" href="https://github.com/NotAShelf/stash/actions">
    <img
      src="https://github.com/NotAShelf/stash/actions/workflows/rust.yml/badge.svg"
      alt="Build Status"
    />
</a>
<a alt="Dependencies" href="https://deps.rs/repo/github/notashelf/stash">
    <img
      src="https://deps.rs/repo/github/notashelf/stash/status.svg"
      alt="Dependency Status"
    />
</a>

Lightweight & feature-rich Wayland clipboard "manager" with fast persistent history and robust multi-media support. Stores and previews clipboard entries (text, images) on the clipboard with a neat TUI and advanced scripting capabilities.

Features

Installation | Usage | Motivation Tips and Tricks

Features

Stash is a feature-rich, yet simple and lightweight clipboard management utility with many features such as but not necessarily limited to:

  • Automatic MIME detection for stored entries
  • Fast persistent storage using SQLite
  • List, search, decode, delete, and wipe clipboard history with ease
  • Backwards compatible with Cliphist TSV format
  • Import clipboard history from TSV (e.g., from cliphist list)
  • Image preview (shows dimensions and format)
  • Text previews with customizable width
  • De-duplication, whitespace prevention and entry limit control
  • Automatic clipboard monitoring with stash watch
  • Configurable auto-expiry of old entries in watch mode as a safety buffer
  • Drop-in replacement for wl-clipboard tools (wl-copy and wl-paste)
  • Sensitive clipboard filtering via regex (see below)
  • Sensitive clipboard filtering by application (see below)

See usage section for more details.

Installation

With Nix

Nix is the recommended way of downloading Stash. You can install it using Nix flakes using nix profile add if on non-nixos or add Stash as a flake input if you are on NixOS.

{
  # Add Stash to your inputs like so
  inputs.stash.url = "github:NotAShelf/stash";

  outputs = { /* ... */ };
}

Then you can get the package from your flake input, and add it to your packages to make stash available in your system.

{inputs, pkgs, ...}: let
  stashPkg = inputs.stash.packages.${pkgs.stdenv.hostPlatform}.stash;
in {
  environment.systemPackages = [stashPkg];

  # Additionally feel free to add the Stash package in `systemd.packages` to
  # automatically run the Stash watch daemon, which will watch your primary
  # clipboard for changes and persist them.
  systemd.packages = [stashPkg];
}

If you want to give Stash a try before you switch to it, you may also run it one time with nix run.

nix run github:NotAShelf/stash -- watch # start the watch daemon

Without Nix

You can also install Stash on any of your systems without using Nix. New releases are made when a version gets tagged, and are available under GitHub Releases. To install Stash on your system without Nix, either:

  • Download a tagged release from GitHub Releases for your platform and place the binary in your $PATH. Instructions may differ based on your distribution, but generally you want to download the built binary from releases and put it somewhere like /usr/bin or ~/.local/bin depending on your distribution.
  • Build and install from source with Cargo:

bash cargo install --git https://github.com/notashelf/stash

Usage

[!NOTE] It is not a priority to provide 1:1 backwards compatibility with Cliphist. While the interface is almost identical, Stash chooses to build upon Cliphist's design and extend existing design choices. See Migrating from Cliphist for more details.

The command interface of Stash is only slightly different from Cliphist. In most cases, you may simply replace cliphist with stash and your commands, aliases or scripts will continue to work as intended.

Some of the commands allow further fine-graining with flags such as --type or --format to allow specific input and output specifiers. See --help for individual subcommands if in doubt.

$ stash help
Wayland clipboard manager

Usage: stash [OPTIONS] [COMMAND]

Commands:
  store   Store clipboard contents
  list    List clipboard history
  decode  Decode and output clipboard entry by id
  delete  Delete clipboard entry by id (if numeric), or entries matching a query (if not). Numeric arguments are treated as ids. Use --type to specify explicitly
  db      Database management operations
  import  Import clipboard data from stdin (default: TSV format)
  watch   Start a process to watch clipboard for changes and store automatically
  help    Print this message or the help of the given subcommand(s)

Options:
      --max-items <MAX_ITEMS>
          Maximum number of clipboard entries to keep [default: 18446744073709551615]
      --max-dedupe-search <MAX_DEDUPE_SEARCH>
          Number of recent entries to check for duplicates when storing new clipboard data [default: 20]
      --preview-width <PREVIEW_WIDTH>
          Maximum width (in characters) for clipboard entry previews in list output [default: 100]
      --db-path <DB_PATH>
          Path to the `SQLite` clipboard database file [env: STASH_DB_PATH=]
      --excluded-apps <EXCLUDED_APPS>
          Application names to exclude from clipboard history [env: STASH_EXCLUDED_APPS=]
      --ask
          Ask for confirmation before destructive operations
  -v, --verbose...
          Increase logging verbosity
  -q, --quiet...
          Decrease logging verbosity
  -h, --help
          Print help
  -V, --version
          Print version

Store an entry

echo "some clipboard text" | stash store

List entries

stash list

Stash list will list all entries in an interactive TUI that allows navigation and copying/deleting entries. This behaviour is EXCLUSIVE TO TTYs and Stash will display entries in Cliphist-compatible TSV format in Bash scripts. You may also enforce the output format with stash list --format <tsv | json>.

You may also view your clipboard with the addition of expired entries, i.e., entries that have reached their TTL and are marked as expired, using the --expired flag as stash list --expired. Expired entries are not cleaned up when using this flag, allowing you to inspect them before running cleanup.

Decode an entry by ID

stash decode <input ID>

[!TIP] Decoding from dmenu-compatible tools:

bash stash list | tofi | stash decode

Delete entries matching a query

stash delete --type [id | query] <text or ID>

By default stash will try to guess the type of an entry, but this may not be desirable for all users. If you wish to be explicit, pass --type to stash delete.

Delete multiple entries by ID (from a file or stdin)

stash delete --type id < ids.txt

Wipe all entries

[!WARNING] This command is deprecated, and will be removed in v0.4.0. Use stash db wipe instead.

stash wipe

Database management

Stash provides a db subcommand for database maintenance operations:

stash db wipe [--expired] [--ask]
stash db vacuum
stash db stats
  • stash db wipe: Remove all entries from the database. Use --expired to only wipe expired entries instead of all entries. Requires --ask confirmation by default.
  • stash db vacuum: Optimize the database using SQLite's VACUUM command, reclaiming space and improving performance.
  • stash db stats: Display database statistics including total/active/expired entry counts, storage size, and page information. This is provided purely for convenience and the rule of the cool.

Watch clipboard for changes and store automatically

stash watch

This runs a daemon that monitors the clipboard and stores new entries automatically. This is designed as an alternative to shelling out to wl-paste --watch inside a Systemd service or XDG autostart. You may find a premade Systemd service in contrib/. Packagers are encouraged to vendor the service unless adding their own.

Automatic Clipboard Clearing on Expiration

When stash watch is running and a clipboard entry expires, Stash will detect if the current clipboard still contains that expired content and automatically clear it. This prevents stale data from remaining in your clipboard after an entry has expired from history.

[!NOTE] This behavior only applies when the watch daemon is actively running. Manual expiration or deletion of entries will not clear the clipboard.

MIME Type Preference for Watch

stash watch supports a --mime-type (short -t) option that lets you prioritise which MIME type the daemon should request from the clipboard when multiple representations are available.

  • any (default): Request any available representation (current behaviour).
  • text: Prefer text representations (e.g. text/plain, text/html).
  • image: Prefer image representations (e.g. image/png, image/jpeg) so that image copies from browsers or file managers are stored as images rather than HTML fragments.

Example: prefer images when running the watch daemon

stash watch --mime-type image

This is useful when copying images from browsers or file managers where the clipboard may offer both HTML and image representations; selecting image will ask the compositor for image data first. Most users will be fine using the default value (any) but in the case your browser (or other applications!) regularly misrepresent data, you might wish to prioritize a different type.

Options

Some commands take additional flags to modify Stash's behavior. See each commands --help text for more details. The following are generally standard:

  • --db-path <path>: Custom database path
  • --max-items <N>: Maximum number of entries to keep (oldest trimmed)
  • --max-dedupe-search <N>: Deduplication window size
  • --preview-width <N>: Text preview max width for list
  • --version: Print the current version and exit

Sensitive Clipboard Filtering

Stash can be configured to avoid storing clipboard entries that match a sensitive pattern, using a regular expression. This is useful for preventing accidental storage of secrets, passwords, or other sensitive data. You don't want sensitive data ending up in your persistent clipboard, right?

The filter can be configured in one of three ways, as part of two separate features.

Clipboard Filtering by Entry Regex

This can be configured in one of two ways. You can use the environment variable STASTH_SENSITIVE_REGEX to a valid regex pattern, and if the clipboard text matches the regex it will not be stored. This can be used for trivial secrets such as but not limited to GitHub tokens or secrets that follow a rule, e.g. a prefix. You would typically set this in your ~/.bashrc or similar but in some cases this might be a security flaw.

The safer alternative to this is using Systemd LoadCrediental. If Stash is running as a Systemd service, you can provide a regex pattern using a crediental file. For example, add to your stash.service:

LoadCredential=clipboard_filter:/etc/stash/clipboard_filter

The file /etc/stash/clipboard_filter should contain your regex pattern (no quotes). This is done automatically in the vendored Systemd service. Remember to set the appropriate file permissions if using this option.

The service will check the credential file first, then the environment variable. If a clipboard entry matches the regex, it will be skipped and a warning will be logged.

[!TIP] Example regex to block common password patterns:

(password|secret|api[_-]?key|token)[=: ]+[^\s]+

For security reasons, you are recommended to use the regex only for generic tokens that follow a specific rule, for example a generic prefix or suffix.

Clipboard Filtering by Application Class

Stash allows blocking an entry from the persistent history if it has been copied from certain applications. This depends on the use-toplevel feature flag and uses the the wlr-foreign-toplevel-management-v1 protocol for precise focus detection. While this feature flag is enabled (the default) you may use --excluded-apps in, e.g., stash watch or set the STASH_EXCLUDED_APPS environment variable to block entries from persisting in the database if they are coming from your password manager for example. The entry is still copied to the clipboard, but it will never be put inside the database.

This is a more robust alternative to using the regex method above, since you likely do not want to catch your passwords with a regex. Simply pass your password manager's window class to --excluded-apps and your passwords will be only copied to the clipboard.

[!TIP] Example startup command for Stash daemon:

stash --excluded-apps Bitwarden watch

Motivation

I've been a long-time user of Cliphist. You can probably tell by the number of times it has been mentioned in the README, if not for the attributions section, that Stash is clearly inspired and adapted from it. It's actually a great clipboard manager if your needs are simple, but mine aren't. I need an all-in-one solution, that I can freely hack on, with simple solutions to complex problems that I've had with managing my clipboard. I wanted it to be scriptable and interactive, I wanted it to be performant, I wanted it to be...

You get the point

Extension points exported contracts — how you extend this code

WipeCommand (Interface)
(no doc) [1 implementers]
src/commands/wipe.rs
ClipboardDb (Interface)
(no doc) [1 implementers]
src/db/mod.rs
ImportCommand (Interface)
(no doc) [1 implementers]
src/commands/import.rs
StoreCommand (Interface)
(no doc) [1 implementers]
src/commands/store.rs
WatchCommand (Interface)
(no doc) [1 implementers]
src/commands/watch.rs
DecodeCommand (Interface)
(no doc) [1 implementers]
src/commands/decode.rs

Core symbols most depended-on inside this repo

push
called by 25
src/commands/watch.rs
store_entry
called by 17
src/db/mod.rs
report_error
called by 12
src/main.rs
preview_entry
called by 6
src/db/mod.rs
search_filter
called by 4
src/commands/list.rs
count_entries
called by 4
src/db/mod.rs
negotiate_mime_type
called by 3
src/commands/watch.rs
delete
called by 3
src/commands/delete.rs

Shape

Function 98
Method 53
Class 10
Interface 9
Enum 3

Languages

Rust100%

Modules by API surface

src/db/mod.rs66 symbols
src/commands/watch.rs23 symbols
src/mime.rs21 symbols
src/commands/list.rs19 symbols
src/multicall/wl_paste.rs11 symbols
src/multicall/wl_copy.rs9 symbols
src/wayland/mod.rs6 symbols
src/main.rs5 symbols
src/commands/wipe.rs2 symbols
src/commands/store.rs2 symbols
src/commands/query.rs2 symbols
src/commands/import.rs2 symbols

For agents

$ claude mcp add stash \
  -- python -m otcore.mcp_server <graph>

⬇ download graph artifact