Clipboard monitor that watches for specific content patterns and lets you route them to configured targets ā instantly, with a single keypress.
Ctrl+F10)Enterflowchart TD
CB[š Clipboard] -->|text copied| MON[Clipboard Monitor]
MON -->|regex match| POPUP[clipygo Popup]
HK[āØļø Global Hotkey] -->|Ctrl+F10| POPUP
POPUP --> CONTENT[Clipboard Content]
POPUP --> TARGETS[Target List]
TARGETS --> PA[šÆ Target A]
TARGETS --> PB[šÆ Target B]
TARGETS --> PC[šÆ Target C]
PA & PB & PC -->|user selects| SEND[Send Request]
SEND -->|JSON over stdin| PLUGIN[Plugin Process\nnode / python / rust / go]
PLUGIN -->|JSON over stdout| RESULT[ā
Success / ā Error]
PLUGIN -->|HTTP| EXT[Teams / Slack / GitHub / ...]
style POPUP fill:#1a1a2e,color:#00d4ff,stroke:#00d4ff
style PLUGIN fill:#1a1a2e,color:#ff6b35,stroke:#ff6b35
style EXT fill:#1a1a2e,color:#00ff88,stroke:#00ff88
cargo install tauri-cli# Clone the repo
git clone https://github.com/it-atelier-gn/clipygo.git
cd clipygo
# Install frontend dependencies
npm install
# Run in development mode
cargo tauri dev
# Build a release binary
cargo tauri build
Settings are persisted to %APPDATA%\clipygo\config.json and managed through the in-app settings window (tray icon ā Settings).
| Setting | Default | Description |
|---|---|---|
autostart |
true |
Launch clipygo on system boot |
global_shortcut |
Ctrl+F10 |
Hotkey to show the popup |
regex_list |
see below | Patterns that trigger the popup automatically |
registry_url |
registry.json | URL of the plugin registry |
https://code-with-me\.jetbrains\.com/[a-zA-Z0-9\-_]+ # JetBrains Code With Me
https://[a-z0-9\-]+\.zoom\.us/j/[0-9]+ # Zoom meeting links
https://meet\.google\.com/[a-z]{3}-[a-z]{4}-[a-z]{3} # Google Meet
https://teams\.microsoft\.com/l/meetup-join/[^\s]+ # Microsoft Teams meetings
Add your own patterns in the settings window under Pattern Recognition.
clipygo uses a persistent subprocess model for target providers. A plugin is any executable that reads JSON requests from stdin and writes JSON responses to stdout ā one JSON object per line. The process stays alive for the lifetime of the session.
Open Settings ā Plugins ā enter a name and the command to run:
Name: My Plugin
Command: node C:\plugins\my-plugin\index.js
The command can be any executable or interpreter ā compiled binaries, Node.js scripts, Python scripts, etc.
Every request is a single line of JSON. Every response is a single line of JSON.
| Command | Required | Description |
|---|---|---|
get_info |
Yes | Plugin name, version, description, author |
get_targets |
Yes | List of targets the plugin provides |
send |
Yes | Deliver clipboard content to a target |
get_config_schema |
No | JSON Schema + current values for the settings UI |
set_config |
No | Apply config values saved by the user |
get_info ā called on startup to verify the plugin{"command":"get_info"}
{"name":"My Plugin","version":"1.0.0","description":"...","author":"..."}
get_targets ā returns all available targets for this plugin{"command":"get_targets"}
{
"targets": [
{
"id": "unique-target-id",
"provider": "My Plugin",
"formats": ["text"],
"title": "Target Display Name",
"description": "Short description",
"image": "<base64 PNG>"
}
]
}
send ā send clipboard content to a target{"command":"send","target_id":"unique-target-id","content":"clipboard text here","format":"text"}
{"success":true}
{"success":false,"error":"Something went wrong"}
get_config_schema (optional) ā return a JSON Schema and current values for the settings UI{"command":"get_config_schema"}
{
"schema": {
"type": "object",
"title": "My Plugin",
"properties": {
"api_key": { "type": "string", "title": "API Key", "description": "Your secret API key", "format": "password" },
"verbose": { "type": "boolean", "title": "Verbose Logging" },
"mode": { "type": "string", "title": "Mode", "enum": ["fast","slow"], "enumTitles": ["Fast","Slow"], "default": "fast" }
},
"required": ["api_key"]
},
"values": { "api_key": "", "verbose": false, "mode": "fast" }
}
If this command is implemented, clipygo shows a ā Configure button next to the plugin in Settings. Supported field types: string (text input), string with format: "password" (password input), string with enum (select), boolean (toggle).
set_config (optional) ā apply configuration values saved by the user{"command":"set_config","values":{"api_key":"secret","verbose":true,"mode":"fast"}}
{"success":true}
The plugin is responsible for persisting the values (e.g. to its own config file).
clipygo auto-restarts a crashed plugin on the next request. After 3 consecutive failures the plugin is marked as errored and paused ā remove and re-add it in settings to reset.
clipygo-plugin-demo is a minimal reference implementation. Pre-built binaries are available on its releases page, or install it directly from the plugin registry in Settings.
const readline = require('readline');
const rl = readline.createInterface({ input: process.stdin });
rl.on('line', (line) => {
const req = JSON.parse(line);
if (req.command === 'get_info') {
respond({ name: 'My Plugin', version: '1.0.0', description: '...', author: '...' });
} else if (req.command === 'get_targets') {
respond({
targets: [{
id: 'my-target',
provider: 'My Plugin',
formats: ['text'],
title: 'My Target',
description: 'Does something useful',
image: ''
}]
});
} else if (req.command === 'send') {
// do something with req.target_id, req.content, req.format
respond({ success: true });
}
});
function respond(obj) {
process.stdout.write(JSON.stringify(obj) + '\n');
}
import sys, json
for line in sys.stdin:
req = json.loads(line.strip())
if req['command'] == 'get_info':
print(json.dumps({'name': 'My Plugin', 'version': '1.0.0', 'description': '...', 'author': '...'}), flush=True)
elif req['command'] == 'get_targets':
print(json.dumps({'targets': [{'id': 'my-target', 'provider': 'My Plugin', 'formats': ['text'], 'title': 'My Target', 'description': '...', 'image': ''}]}), flush=True)
elif req['command'] == 'send':
# do something with req['target_id'], req['content'], req['format']
print(json.dumps({'success': True}), flush=True)
The built-in registry browser (Settings ā Plugin Registry) lets you browse and install plugins with one click. The default registry is hosted at it-atelier-gn/clipygo-plugins.
To publish a plugin to the registry, see the registry README.
clipygo/
āāā src/ # SvelteKit frontend
ā āāā routes/
ā ā āāā main/ # Popup window (clipboard content + target list)
ā ā āāā settings/ # Settings window
ā āāā app.css # Global styles
āāā src-tauri/ # Tauri / Rust backend
āāā src/
āāā lib.rs # App setup, clipboard monitor, global shortcut
āāā targets.rs # TargetProvider trait + coordinator
āāā settings.rs # Settings model + persistence
āāā trayicon.rs # System tray setup
āāā target_providers/
āāā subprocess.rs # Persistent subprocess plugin runner
TargetProviderCoordinator::snapshot() extracts providers before any .await, avoiding MutexGuard held across async boundariestmuntaner-keyring is available for providers that need to store secrets (e.g. OAuth tokens)Contributions are welcome. For substantial changes, open an issue first to discuss the approach.
# Run checks before submitting
cd src-tauri && cargo check && cargo clippy
MIT Ā© 2026 Georg Nelles