A free, open-source selection bar for macOS: select text, and a small bar of actions appears next to it. It aims to run existing PopClip extensions unchanged.
Status: pre-alpha, milestone M3 (the JavaScript runtime) in progress. There is an app that builds and nothing anyone should rely on:
- M1 assembled the bar, the five built-in actions, the menu bar item, Settings and the onboarding flow. Nobody has run it for long enough to call it working.
- M2 built the extension parser, the store and the six non-JavaScript action types, behind consent. The parser loads
368 of the 381 extensions in PopClip's public repository (
swift run pappu-dev corpus load), and every one that loads also installs into the store. Its manual checklist has not been run. - M3 has a sandboxed JavaScript helper with one isolated world per extension, and PopClip's language environment:
timers,
Buffer,URLand the rest, the 19 bundled libraries,require, and TypeScript. JavaScript and TypeScript actions run, and so do module extensions' actions, once the extension is approved. Scripts can use thepopclipmethods,util,pasteboardandRichString, each call checked by the app against what the extension was granted. An action that asks for HTML or RTF gets the selection's styling where the app gives it through Accessibility. External scripts, population functions and network access are still to come.
The M0 spikes still need a Mac with a person at it (what is left), and SpikeLab is the
throwaway app that runs them.
PappuClip is an independent project. It is not affiliated with, endorsed by, or derived from the code of PopClip or Pilotmoon Software. "PopClip" is their trademark and is used here only to describe compatibility.
| Product requirements | What it does, for whom, and the requirement IDs everything else refers to |
| Safety specification | Clipboard transactions, invocation safety, consent |
| Extension platform | Package format and the JavaScript runtime |
| Architecture | Processes, modules, and the mechanisms that enforce the safety rules |
| Implementation plan | Milestones M0 to M6 |
| Spike reports | What M0 found, and what is left to run |
Requires macOS 15 or later, Xcode 26 (Swift 6) and XcodeGen
(brew install xcodegen).
# The package: every module, the unit tests, the repository checks
cd Packages/PappuKit
swift build
swift test
swift run pappu-dev trace check # Tests/traceability.yaml against the design documents and the tests
# The app targets: `Scripts/build.sh [scheme] [configuration]`, default SpikeLab Debug
Scripts/setup-dev-signing.sh # once per Mac; see below
Scripts/build.sh PappuClip # generates App/PappuClip.xcodeproj and builds the app into build/
open build/DerivedData/Build/Products/Debug/PappuClip.app
Scripts/build.sh # SpikeLab, for the M0 spikes
open build/DerivedData/Build/Products/Debug/SpikeLab.appPappuClip is a menu-bar agent: there is no Dock icon and no window at launch, only a paperclip in the menu bar and,
the first time, a window explaining why it wants the Accessibility permission. Without that permission no bar appears
on a selection, and the first item in the menu says so. tccutil reset Accessibility app.pappuclip.PappuClip puts a
Mac back to never having been asked.
macOS ties the Accessibility permission to an app's code signature. An unsigned or ad-hoc-signed build gets a new
signature every time it is compiled, so macOS forgets the permission on every rebuild.
Scripts/setup-dev-signing.sh creates a self-signed certificate in your login keychain that stays the same between
builds. It is trusted by nobody and cannot be used to distribute anything. To use a certificate you already have:
PAPPU_SIGN_IDENTITY="Apple Development: Your Name (TEAMID)" Scripts/build.shWithout either, the build falls back to ad-hoc signing and warns.
Use the SpikeLab window, or:
Scripts/run-spike.sh --list
Scripts/run-spike.sh spike-2-taps --state "Accessibility only"Results are written to Tests/results/ (format). Do not run the SpikeLab binary
straight from a shell for anything you intend to keep: macOS then treats your terminal as the responsible process,
and every permission result describes the terminal.
Packages/PappuKit holds all the code as one SwiftPM package with a target per module; App/ holds the thin Xcode
targets that host it. Architecture §15 has the full map.
MIT. The app reuses no code from the GPL-3.0 selection-detection projects, so the permissive option in PRD §13 applies. Extensions are separate works and may use any licence.