Give Claude Code the "Clicky" persona — a friendly, lowercase macOS
companion that captures your screens, answers in short conversational
replies, flags UI elements with a [POINT:x,y:label:screenN] protocol,
and installs + launches the full native Clicky.app on demand.
Runs entirely off your existing Claude Code subscription. No Anthropic
API key. No Cloudflare Worker. Zero npm dependencies — everything is
bundled as TypeScript scripts executed via npx -y bun.
macOS only for v1. Apple Silicon only for the DMG install path —
Intel Macs can run the plugin scripts but must install the native app
manually (the install subcommand looks for arm64 DMGs on GitHub
Releases). Linux and Windows are not targets.
Use npx skills to install the skill directly into your Claude Code setup:
# Install the skill
npx skills add proyecto26/openclicky
# List what's inside the package
npx skills add proyecto26/openclicky --listThis drops the skill into your .claude/skills/ directory.
Install via Claude Code's built-in plugin system:
# Add the marketplace
/plugin marketplace add proyecto26/openclicky
# Install the plugin
/plugin install openclickyClone the repo and copy the skills folder into your project's Claude config:
git clone https://github.com/proyecto26/openclicky.git
cp -r openclicky/skills/* .claude/skills/Add as a submodule for easy updates:
git submodule add https://github.com/proyecto26/openclicky.git .claude/openclickyThen reference skills from .claude/openclicky/skills/.
- Fork this repository.
- Customize the persona, subcommands, or install flow for your needs.
- Clone your fork and use any of the options above.
- macOS 14.2+ (for native screen capture APIs).
npx— ships with any recent Node.js install.bundoes not need to be pre-installed;#!/usr/bin/env -S npx -y bundownloads it on first run (~5–10 s delay once) and caches it.- Screen Recording permission — grant it to the terminal emulator
that hosts
bun(or to Claude Code itself) inSystem Settings → Privacy & Security → Screen Recording. Without this,capturefails with "could not create image from display". - (Optional) Accessibility permission — grant it to the same
terminal so the
statussubcommand's accessibility probe returnsgranted.
Just talk to Claude:
"openopenclicky, what's on my screen?"
The skill captures every connected display, reads the JPEGs, replies in
a sentence or two, and optionally appends a [POINT:x,y:label:screenN]
tag flagging a relevant UI element.
-
A skill (
skills/openclicky/SKILL.md) that loads when you say "openclicky", ask "what's on my screen", request "point at the save button", etc. -
A CLI dispatcher (
skills/openclicky/scripts/main.ts) with six subcommands that the skill tells Claude to invoke via Bash:Subcommand What it does installInstall the native Clicky.appon demandlaunchLaunch the installed app captureScreenshot every connected display, emit a JSON manifest pointRender a POINT coordinate as a human-readable line speakSpeak text aloud (say / VibeVoice / ElevenLabs) statusEnvironment health report
Just talk to Claude:
You: openclicky, what's on my screen?
Claude: (invokes capture, reads the manifest, replies) looks like you're in figma with the components panel on the left. that rectangle in the middle is your current selection.
[POINT:960,540:selected rectangle]
# All subcommands are directly runnable:
bun skills/openclicky/scripts/main.ts help
bun skills/openclicky/scripts/main.ts status --json
bun skills/openclicky/scripts/main.ts capture
bun skills/openclicky/scripts/main.ts point --x 1100 --y 42 --label "color inspector"
bun skills/openclicky/scripts/main.ts speak "hello from openclicky"
bun skills/openclicky/scripts/main.ts install --dry-run
bun skills/openclicky/scripts/main.ts launchinstall tries, in order:
brew install proyecto26/tap/openclicky(preferred).- Download the latest signed DMG from
github.com/proyecto26/openclicky/releases,
verify SHA256, mount, copy
.appinto/Applications/. - Print a manual URL as a last resort.
Once installed, launch opens the app (or you can click it from
/Applications/). The native app gives you the full "teacher" Clicky
experience:
- Always-on cursor buddy — a blue triangle follows the mouse at 60 Hz with a spring animation, offset below-right of the cursor.
- Push-to-talk (
⌃⌥) — the triangle becomes a live waveform while you're speaking, then a spinner while Claude thinks, then speaks the reply through macOS Speech or ElevenLabs. - Streaming response bubble — Claude's reply appears in a rounded bubble beside the buddy, updating as tokens stream in. Auto-fades ~6 s after the turn finishes.
- POINT flight — when Claude emits a
[POINT:x,y:label]tag, the buddy flies along a Bézier arc to that pixel on the correct display, holds with a label chip for 3 s, then flies back to the cursor. - Esc to cancel — works from any app. Stops the Claude roundtrip,
halts TTS mid-sentence, kills any in-flight POINT flight, and clears
the bubble. A 250 ms debounce on voice dispatch means rapid re-presses
of
⌃⌥always resolve to exactly one Claude call, for your most recent utterance. - Menu-bar panel — status icon with a typed "Test Claude" input, permission guidance, an ElevenLabs settings pane (API key + voice ID stored in the macOS Keychain), and a session history clear.
The plugin and the native app do not talk to each other — they're independent experiences you choose between.
Default engine is macOS say. Two optional upgrades:
Run VibeVoice yourself from its repo and point the plugin at it:
export OPENCLICKY_VIBEVOICE_URL=http://localhost:3000
export OPENCLICKY_VIBEVOICE_SPEAKER=Carter # optional, default CarterIf the server is unreachable the plugin falls back to say with a
one-line warning.
export OPENCLICKY_ELEVENLABS_API_KEY=sk-...
export OPENCLICKY_ELEVENLABS_VOICE_ID=kPzsL2i3teMYv0FxEYQ6 # optionalThe plugin never ships, bundles, or exfiltrates any API key.
| Variable | Effect |
|---|---|
OPENCLICKY_DATA_DIR |
Override state dir (default ~/Library/Application Support/openclicky/) |
OPENCLICKY_APP_PATH |
Explicit path to an installed Clicky.app |
OPENCLICKY_VIBEVOICE_URL |
Local VibeVoice HTTP server URL |
OPENCLICKY_VIBEVOICE_SPEAKER |
VibeVoice speaker name |
OPENCLICKY_ELEVENLABS_API_KEY |
User-supplied ElevenLabs key |
OPENCLICKY_ELEVENLABS_VOICE_ID |
ElevenLabs voice ID |
State written under $OPENCLICKY_DATA_DIR:
openclicky/
├── screenshots/ # multi-display JPEGs emitted by `capture`
├── downloads/ # DMGs downloaded by `install` (kept for inspection)
└── config.json # future: plugin config
captureerrors with "could not create image from display" — Screen Recording permission isn't granted. Grant it to the terminal that runsbun, then re-run.installreports "brew available → brew install failed" — the caskproyecto26/tap/openclickyisn't published yet (or the tap isn't tapped). The script automatically falls back to the DMG download.statussaysclaudeCLI.installed: false— theclaudebinary isn't in$PATH. Install it from claude.com/claude-code./openclicky …doesn't trigger the skill — make sure the plugin is loaded. Runclaude --debugto see skill discovery logs, or add the plugin via--plugin-dir.
- Zero npm dependencies. All scripts use Node/bun built-ins
(
node:fs,node:child_process,node:crypto,node:stream/promises). Nopackage.json, nobun.lockb. - Structure mirrors notebooklm-ai-plugin exactly — shebang at the
top of
main.ts, per-subcommand modules, hand-rolled arg parser. - macOS-only via explicit
assertDarwin()gates. - No LLM calls from the plugin — the host Claude Code session is the LLM. Plugin scripts are pure tool invocations.
See docs/specs/openclicky.md for the full spec and
docs/plan/implementation-plan.md for milestones + dependencies.
MIT. See LICENSE.