Better Clipboard Manager (BCM) is a Python 3.12+ Linux/X11 clipboard manager. It provides a GTK/AppIndicator tray menu, PRIMARY/CLIPBOARD sync, local text/image history, first-run YAML config creation, and optional systemd user-service installation.
Supported public surfaces are the bcm CLI, YAML configuration, make targets, and systemd service. Python modules under bcm are internal implementation details, not a stable API or plugin interface.
main.pyparses CLI flags, enforces the single-instance lock, initializes config/logging, and owns shutdown signal handling.app.pyis the imperative shell: X11 polling, sync orchestration, history mutation, tray integration, persistence, cleanup, and shutdown behavior.sync.py, most history transforms, and image/path helpers keep side-effect-light logic isolated for unit testing.clipboard.pyis the X11 boundary.DisplayProtocolandClipboardReaderallow tests to exercise clipboard behavior without a real display.types.pyholds frozen dataclasses for runtime state/history entries plus configTypedDicts.
- BCM targets X11. Wayland-only/headless sessions are unsupported unless an X11 compatibility environment, such as Xvfb, provides
DISPLAY. - Text clipboard writes use external tools (
xclip/xsel) instead of long-running selection ownership. Image copy-back uses GTK clipboard APIs because image paste targets need richer metadata. - History is local cache-like state, not a stable file format. Persisted history may contain secrets; storage paths and log files use private permissions.
- Stored images use SHA-256 content-addressed filenames for deduplication. History-loaded image paths must stay under the configured images directory.
- Logs go to stdout/stderr by default. Log rotation is intentionally delegated to systemd journal or external rotation for configured file output.
--dry-runmust avoid clipboard writes, history mutation, image/thumbnail writes, cleanup deletion, and persistence writes.
| File | Purpose |
|---|---|
src/bcm/main.py |
CLI entry point, instance lock, signal handling |
src/bcm/app.py |
Runtime orchestration and main loop |
src/bcm/clipboard.py |
X11 clipboard reads/writes and test protocols |
src/bcm/clipboard_tool.py |
xclip/xsel subprocess wrappers |
src/bcm/sync.py |
Pure PRIMARY/CLIPBOARD sync decision logic |
src/bcm/history.py |
History transforms, JSON persistence, path validation |
src/bcm/images.py |
Image storage, thumbnails, cleanup helpers |
src/bcm/tray.py |
GTK/AppIndicator tray UI |
src/bcm/config.py |
Defaults, YAML load/merge, validation, path resolution |
src/bcm/logger.py |
Logging, private file setup, status tracking |
src/bcm/types.py |
Dataclasses, enums, config TypedDicts |
config/default.yaml |
User-facing default/starter configuration template |
make install # Install dependencies with uv
make run # Run from source
make test # All pytest tests under Xvfb with release policy
make coverage # All pytest tests with coverage threshold under Xvfb
make type-check # Source MyPy
make type-check-tests # Test-suite MyPy
make build # PyInstaller Linux release binary
make check # Full local release gate: format, lint, mypy, test, coverage- Config changes: update
get_default_config()insrc/bcm/config.py,_CONFIG_SCHEMA,src/bcm/types.py,config/default.yaml, and relevant docs/tests. - New history entry types: add frozen dataclass and
ClipboardEntryunion member intypes.py; update serialization/deserialization and path/security validation inhistory.py; update tray rendering if visible to users. - Clipboard behavior changes: cover pure sync decisions in unit tests and X11/tool boundaries with existing mocks or Xvfb tests.