Build PastePal
A clipboard manager whose interesting engineering is capturing everything fast and searchably, and whose entire design constraint is that a meaningful fraction of what passes through a clipboard must never be written down.
Before step 1
Everything below is assumed from the first step. Tick each one when you actually have it, not when you plan to.
- installfree
Why Runs the local application.
Get it nodejs.org, or nvm install 22. open ↗
Verify
node --version prints v22 or higher - installfree
Why The marker is how a password manager tells you not to record something, and reading it is platform-specific and easy to miss entirely.
Get it Your platform's clipboard interface, and find the marker's name in its documentation before writing the capture path.
Verify
Content copied from a password manager is identifiable as marked - installfree
Why The database encryption key has to live somewhere better than beside the database.
Get it Your platform's credential store interface.
Verify
A key stores and retrieves and is not readable from a plain file - decidefree
Why Deciding what never to record after a month of recording is deciding it too late, since the data already exists.
Get it List applications to exclude and the content shapes that must never be stored, erring wide.
Verify
The list is loaded by the capture path before the first run - have readyfree
Why The single most important behaviour is not recording what a password manager copies, and that is only verifiable against a real one.
Get it Any password manager that sets the sensitivity marker.
Verify
Copying a password from it produces no stored item
Data model
Create these before the first phase that stores anything. Changing a table later is the expensive kind of change.
- items(id, kind, content, source_app, copied_at, pinned, collection_id) · kind is text, image, file_ref or rich - collections(id, name, ordinal) · saved snippets, kept indefinitely unlike history - exclusions(id, rule_kind, pattern, created_at) · rule_kind is app, shape or marker - skipped(at, reason, source_app) · that something was excluded, never what it was - settings(key, value) · hotkey, retention, encryption state - The skipped table records that an exclusion fired and why, and deliberately never records the content it excluded, because that record would be exactly the thing being protected.
Environment variables
These go in a .env file the app reads at startup. The pack's .env.example is this table as a file · copy it, never commit the filled-in version.
| Variable | Needed | Example | Where the value comes from |
|---|---|---|---|
DB_PATH | required | ~/.local/share/pastepal/history.db | Encrypted history and collections. |
DB_KEY_REFsecret | required | a keychain item reference | The encryption key lives in the platform keychain, not beside the database. |
HISTORY_LIMIT | required | 200 | Bounded. An unbounded clipboard log is a growing liability. |
EXCLUSIONS_PATH | required | ./config/exclusions.txt | Applied in the capture path, before anything is written. |
HONOUR_SENSITIVITY_MARKER | required | always | Present as a constant. It is how a password manager says do not record this. |
SYNC_HISTORY | required | never | Present as a constant. Only deliberately saved collections sync. |
The build, in order
Not capturing what must not be captured
Sensitive content never reaches disk in the first place.
Password managers set it. Ignoring it is the first failure.
Files
src/capture.tsCard numbers, keys and tokens, checked in the capture path.
Files
src/exclusions.tstests/exclusions.test.tsThe record would otherwise be the thing you were protecting.
Files
src/skipped.ts
done when · tick each as it passeswatch out- Filtering sensitive items when the history is displayed leaves them in the database, the backups and any crash report, so the protection exists only in the interface. Apply exclusions in the capture path, and record that something was skipped without recording what it was.
A history that is faster than not having one
Reaching an item from three copies ago takes under a second.
The first use of the day is the one that decides the habit.
Files
src/window.tsA rich text item pasted as plain text is a lost item.
Files
src/formats.tsAn unbounded clipboard log is a growing liability.
Files
src/retention.ts
done when · tick each as it passeswatch out- A clipboard manager that takes two seconds to open is slower than scrolling back in the application you copied from, and people stop using it within a week. Pre-warm the window, and measure from keypress to pasted rather than to displayed.
Encrypted at rest, searchable in memory
The stored history is unreadable without the key, and still searchable.
So the key is not sitting beside the database.
Files
src/crypto.tsA plaintext index makes the encryption decorative.
Files
src/search.tstests/no-index.test.tsDecrypted history resident indefinitely defeats the lock.
Files
src/lock.ts
done when · tick each as it passeswatch out- Building a search index for speed writes the content in plaintext beside the encrypted database, which makes the encryption decorative. Search in memory over the decrypted set, and accept the performance cost, which at a bounded history size is negligible.
Things worth keeping
Snippets you use often are saved separately from the rolling history.
A saved snippet should not roll out of history.
Files
src/collections.tsOtherwise the sensitive item persists indefinitely rather than briefly.
Files
src/collections.tsThe whole tool exists to avoid reaching for a mouse.
Files
src/collections.ts
done when · tick each as it passeswatch out- Allowing a user to pin an item that the exclusion rules would have blocked reintroduces exactly the risk, and the item then persists indefinitely rather than rolling out of history. Apply the same rules to collections and explain the refusal rather than silently allowing it.
Sync, export and forgettingproduct builder
History can move between machines or be destroyed completely.
History is transient by definition and multiplying it is pure exposure.
Files
src/sync.tsIncluding memory, not only the database.
Files
src/clear.tsAn exported collection file is plaintext by nature.
Files
src/export.ts
done when · tick each as it passeswatch out- Syncing the rolling history rather than only saved collections multiplies the exposure across every device and every backup of the sync store, for a set of items that are transient by definition. Sync what was deliberately saved, and leave the history local.
That is the whole plan for PastePal. What it deliberately does not cover is below · check the gaps before you call it a replacement.
- Syncing rolling history across devices.
- Optical recognition of copied images.
- Cloud storage of any kind.
- Clipboard-driven automation.
- native Apple apps, iCloud sync, rich content support, and polish
- years of OS-version edge cases
- large extension ecosystem
- cross-device sync
- commercial support and rapid compatibility fixes
- Per-application paste formatting, since pasting into a terminal and a document want different things
- A quick transform on paste such as trimming or case changes, which is the next most common need
- Smarter shape detection tuned from your own skipped log, which needs no content to improve
Need the files? The project pack on the verdict page hands your agent the whole brief · more productivity utilities.