Documentation
CleanCopy is a macOS command-line app: a native clipboard helper for Apple Silicon and Intel, plus a pure TypeScript cleanup engine. Text in, text out — no side effects.
Requires macOS 12 (Monterey) or later and Node.js 18 or later. The package refuses installation on other operating systems rather than installing a command that cannot work.
$ npm install --global cleancopy-cli $ cleancopy doctor # helper, configuration, and state directory ready?
The npm package is cleancopy-cli; the installed command is
cleancopy.
To upgrade, install again and restart the watcher — the running watcher keeps the old version until it restarts. Settings, the event log, and login autostart carry over on their own.
$ npm install --global cleancopy-cli $ cleancopy stop && cleancopy start
Uninstall in this order — the stop must run while the cleancopy command
still exists:
$ cleancopy stop --disable-autostart $ npm uninstall --global cleancopy-cli
Settings and the content-free event log stay in ~/.cleancopy; delete that
directory yourself if you do not want to keep them.
Clean the clipboard once, without the watcher:
$ pbpaste | cleancopy clean | pbcopy
With the watcher running, copies made while a supported terminal is frontmost are
cleaned in place. Copy, then paste as usual. That is the default auto mode.
In manual mode (cleancopy config mode manual) the gesture is a
double copy — press Cmd+C twice in quick succession on the same selection, and the
second copy triggers the clean. If a clean ever goes wrong, the revert hotkey —
cmd+ctrl+z by default, working in both modes — puts the original copy back.
Prints the effective formatting rules, then per block what it was judged to be and why — to stderr, so the cleaned text on stdout stays pipeable.
$ cleancopy clean --explain < copied-output.txt rules: normalizeLineEndings=on, stripAnsi=on, removeInvisibleCharacters=on, …, reflowProse=on, reflowLists=on, … inferred wrap column: 52 [prose] reflow=true conf=0.9 (reads-like-prose) "The deploy failed because the staging config was…" block L1→L2 join score=5 [continues-sentence+2, at-right-edge+2, dangling-word+1] [table] reflow=false conf=0.9 (aligned-columns) "$ kubectl get pods"
Every operation that changes text is a rule, on by default and shared by the watcher and
cleancopy clean: normalizeLineEndings, stripAnsi,
removeInvisibleCharacters, normalizeSpaces,
trimTrailingWhitespace, removeSharedMargin,
reflowProse, reflowLists, collapseProseSpaces,
trimOuterBlankLines. The code, table, log, and unsure-block protections are
not rules — they stay on.
$ cleancopy config rules $ cleancopy config rule reflowProse off $ cleancopy config rules off $ cleancopy clean --disable-rule reflowLists < copied.txt $ cleancopy clean --no-config < copied.txt
config rules lists every rule and its value; config rule
changes one, and config rules off preserves input exactly until
on restores them. Changing a setting restarts a running watcher. The
--disable-rule and --enable-rule options apply to one run
without touching saved settings, and --no-config uses the built-in
defaults plus any overrides.
Four stages, pure text in, text out. Mixed copies are judged block by block.
CleanCopy only considers copies made when a supported terminal is frontmost. Everything else is discarded before its text is read.
Editors with built-in terminals are intentionally excluded, because their copies may be source code from an editor pane.
Add an unsupported terminal by bundle identifier:
$ export CLEANCOPY_TERMINALS=com.example.my-terminal $ cleancopy start
For a login-started watcher, set the variable before running
cleancopy autostart on; the launch agent preserves it. Re-run
cleancopy autostart on after changing the variable or after switching Node
installations.
Settings live in ~/.cleancopy/config.json, or in the directory named by
CLEANCOPY_STATE_DIR. After editing that file by hand, run
cleancopy stop then cleancopy start.
The event log at ~/.cleancopy/cleancopy.log records content-free summaries
such as cleaned copy from iTerm2 (12 lines → 4). Clipboard contents are
never written to disk.
Nothing leaves your machine — there is no network code in the package.
~/.cleancopy/cleancopy.log records content-free summaries only — like
cleaned copy from iTerm2 (12 lines → 4).
The published CLI runs on Node.js 18 or later. Developing and testing it requires Node.js 20 or later, because the test runner (Vitest 4) does not support Node 18.
$ npm install $ npm test $ npm run typecheck $ npm run build $ npm run build:helper $ npm run release:check
release:check builds the universal native helper, runs the full suite, and
shows the exact npm tarball contents. Helper integration tests use a private
pasteboard — never your real clipboard.
Real-world terminal output makes the cleanup engine safer. Add a fixture and run
npm test:
test/fixtures/<short-name>/input.txt test/fixtures/<short-name>/expected.txt
Fixtures that protect code, logs, and tables from accidental prose reflow are especially valuable.