-
Notifications
You must be signed in to change notification settings - Fork 0
Installation
Complete install guide for Keyward across every supported platform. If you just want the fastest path, do the marketplace quick start and jump to the per-platform deps + permissions note for your OS. If you'd rather read the code before trusting it with your prompts, use the manual clone + symlink method — it produces an identical install, just explicit.
See also: Home · Configuration · Troubleshooting · Security-Model · FAQ
- Requirements
- How the install is wired
- Marketplace quick start
- Manual install (clone + symlink)
- Verifying the install
- What "installed but no auto-paste" means
- Updating
- Uninstall
| Requirement | Notes |
|---|---|
| Python 3.9+ | Must be on PATH as python3. The whole runtime is stdlib — no pip install. Check with python3 --version. |
| Claude Code | With plugin + hooks support. Verify hooks load with /hooks. |
| Per-platform automation tools | The clipboard + keystroke backends. These are what differ per OS — see each section below. |
Keyward has no third-party Python dependencies and makes no network calls. Everything is Python standard library plus the OS clipboard/keystroke tools.
Whichever method you use, the end state is the same: Claude Code finds the plugin directory and registers one hook. The hook entry in hooks/hooks.json is literally:
{
"type": "command",
"command": "python3 ${CLAUDE_PLUGIN_ROOT}/hooks/intercept.py",
"timeout": 15
}${CLAUDE_PLUGIN_ROOT} is set by Claude Code to wherever the plugin lives. The hook fires on every UserPromptSubmit. When it detects a secret it saves the value, blocks the original prompt, and spawns scripts/automate_paste.py (detached) to paste a sanitized version back in. The auto-paste step is the only part that needs the per-platform tools; detection and saving work everywhere, including headless (see Configuration and what "installed but no auto-paste" means).
The fastest path. In a Claude Code session:
/plugin marketplace add AlbeMiglio/keyward
/plugin install keyward@keyward
Then restart Claude Code (hooks load at session start; they will not appear in a session that was already running). After restart:
- macOS — grant Accessibility permission to your terminal app, or auto-paste fails silently. See the macOS deps note.
-
Linux — install the per-platform tools (
xdotool+xclipon X11,wtype+wl-clipboardon Wayland). See Linux X11 / Linux Wayland. -
Windows — PowerShell ships with the OS; nothing extra unless group policy blocks
SendKeys.
Then verify with /hooks.
The marketplace install and the manual install are functionally identical. Pick manual if you want the source checked out somewhere you control and readable before first use.
The pattern is the same on every platform — clone the repo, symlink it into ~/.claude/plugins/keyward, install the OS tools, grant any permission, restart, verify — but the exact commands and the deps differ. Each section below is self-contained; follow the one for your OS.
The symlink approach (rather than copying) means a git pull in the clone updates the installed plugin in place. If your platform can't make symlinks, copy instead and re-copy on update.
1. Install platform deps. macOS ships with everything Keyward needs on this platform — osascript, pbcopy, and pbpaste are all built in. Nothing to install.
2. Clone the repo:
git clone https://github.com/AlbeMiglio/keyward.git ~/keyward3. Symlink into the plugin directory:
mkdir -p ~/.claude/plugins
ln -s ~/keyward ~/.claude/plugins/keyward4. Grant Accessibility permission to your terminal app. This is the step people miss. The auto-paste uses osascript → System Events to send Cmd+V + Return, and macOS blocks synthetic keystrokes from apps that lack Accessibility.
- Open System Settings → Privacy & Security → Accessibility
- Click + and add the app you run Claude Code in: Terminal.app, iTerm, Ghostty, Warp, Alacritty, kitty, WezTerm, VS Code's integrated terminal (add Visual Studio Code), etc.
- Toggle it on
- Fully quit and reopen that terminal app — the permission is read at process start
Without this grant, Keyward still saves the secret and puts the sanitized text on your clipboard; you just paste it manually (Cmd+V + Return). See Troubleshooting for confirming the permission with a one-liner.
5. Restart Claude Code. Quit the current session, then:
claude6. Verify — see Verifying the install.
Auto-paste on X11 uses xdotool (keystrokes) plus xclip or xsel (clipboard). X11 permits synthetic input by default, so no permission grant is needed.
1. Install platform deps:
# Debian / Ubuntu
sudo apt install python3 xdotool xclip
# Fedora / RHEL
sudo dnf install python3 xdotool xclip
# Arch
sudo pacman -S python xdotool xclipxsel is an accepted substitute for xclip — Keyward auto-detects whichever is present (xclip is preferred). You need one clipboard tool plus xdotool.
2. Clone the repo:
git clone https://github.com/AlbeMiglio/keyward.git ~/keyward3. Symlink into the plugin directory:
mkdir -p ~/.claude/plugins
ln -s ~/keyward ~/.claude/plugins/keyward4. Restart Claude Code, then verify.
Are you actually on X11? Run
echo $XDG_SESSION_TYPE. If it printswayland, follow the Wayland section instead — Keyward picks its backend fromWAYLAND_DISPLAY/XDG_SESSION_TYPEat runtime, and the X11 tools won't be used under a Wayland session.
⚠️ Wayland auto-paste is compositor-dependent. Synthetic keystroke injection viawtyperequires the compositor to implement thevirtual-keyboard-v1protocol.
Compositor Auto-paste Sway ✅ works Hyprland ✅ works KDE Plasma (KWin) ⚠️ version-dependentGNOME (Mutter) ❌ blocked by default, no fix without an extension If your compositor blocks
wtype, Keyward still saves the secret and sets the clipboard — you finish withCtrl+V+ Enter manually. Consider exportingKEYWARD_DISABLE_PASTE=1(see Configuration) so it doesn't even attempt the keystroke.
1. Install platform deps:
# Debian / Ubuntu
sudo apt install python3 wtype wl-clipboard
# Fedora
sudo dnf install python3 wtype wl-clipboard
# Arch
sudo pacman -S python wtype wl-clipboardwl-clipboard provides wl-copy / wl-paste.
2. Clone the repo:
git clone https://github.com/AlbeMiglio/keyward.git ~/keyward3. Symlink into the plugin directory:
mkdir -p ~/.claude/plugins
ln -s ~/keyward ~/.claude/plugins/keyward4. Test whether your compositor supports wtype before relying on auto-paste:
echo "keyward wtype test" | wl-copy
sleep 2 && wtype -M ctrl v -m ctrl
# focus a text editor during the 2s window; if the text appears, you're goodIf wtype prints Compositor does not support virtual_keyboard_v1 (or nothing pastes), you're on an unsupported compositor. Auto-paste will degrade to "save + clipboard set, paste manually." Set KEYWARD_DISABLE_PASTE=1 in your shell rc to skip the failing keystroke attempt entirely.
5. Restart Claude Code, then verify.
Auto-paste on Windows uses PowerShell: Set-Clipboard / Get-Clipboard for the clipboard and System.Windows.Forms.SendKeys for Ctrl+V + {ENTER}. PowerShell ships with Windows — no extra install beyond Python.
1. Install Python 3.9+ if you don't have it:
winget install Python.Python.3.12…or download from python.org. During the installer, tick "Add python.exe to PATH". Confirm python3 resolves:
python3 --version(If only python works and not python3, see the note in Troubleshooting about the Windows python3 alias / App Execution Aliases.)
2. Clone the repo:
git clone https://github.com/AlbeMiglio/keyward.git "$env:USERPROFILE\keyward"3. Link or copy into the plugins directory:
New-Item -ItemType Directory -Force -Path "$env:USERPROFILE\.claude\plugins"
# Preferred — symlink (needs Administrator OR Developer Mode enabled):
New-Item -ItemType SymbolicLink `
-Path "$env:USERPROFILE\.claude\plugins\keyward" `
-Target "$env:USERPROFILE\keyward"
# Fallback — copy (use this if symlinks aren't available):
Copy-Item -Recurse "$env:USERPROFILE\keyward" "$env:USERPROFILE\.claude\plugins\keyward"To enable Developer Mode (lets non-admin users create symlinks): Settings → Privacy & security → For developers → Developer Mode → On.
4. Restart Claude Code, then verify.
No permission grant is required — SendKeys targets the foreground window by default. Some enterprise group policies disable SendKeys; if yours does, Keyward falls back to clipboard-only mode (secret saved, sanitized text on clipboard, paste manually). See Troubleshooting.
If you run Claude Code inside WSL, the hook executes inside the Linux VM, but the window with focus is hosted by Windows. Crossing that boundary with synthetic keystrokes is fragile and not reliable. Two supported approaches:
Recommended — install on the WSL (Linux) side, accept manual paste:
# inside WSL
git clone https://github.com/AlbeMiglio/keyward.git ~/keyward
mkdir -p ~/.claude/plugins
ln -s ~/keyward ~/.claude/plugins/keywardThen put this in your shell rc (~/.bashrc / ~/.zshrc) so Claude Code inherits it:
export KEYWARD_DISABLE_PASTE=1Detection and saving work normally; auto-paste is skipped (it wouldn't cross to the Windows host reliably anyway). You copy the sanitized text and paste it yourself. If you run an X server (VcXsrv / X410 / GWSL) and Claude Code in an X11 app inside WSL, you can install the Linux X11 tools and get auto-paste within that X session — but the common Windows-host-terminal → WSL setup should use KEYWARD_DISABLE_PASTE=1.
Alternative — run Claude Code natively on Windows instead of in WSL, and follow Windows (native). Then auto-paste works against the foreground Windows window.
In a Claude Code session, run:
/hooks
You should see a UserPromptSubmit entry pointing at intercept.py, e.g.:
UserPromptSubmit → python3 /Users/you/.claude/plugins/keyward/hooks/intercept.py
(The path reflects wherever the plugin is installed.)
Then exercise the detection layer directly — this needs no display server and works on every platform, so it's the cleanest proof the engine runs:
echo '{"user_prompt": "deploy with ghp_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"}' \
| python3 ~/.claude/plugins/keyward/scripts/detect.pyExpected output (a github_pat_classic slot, source: "regex"):
{"secrets": [{"name": "github_pat_classic", "value": "ghp_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "span": [12, 52], "source": "regex"}], "raw_mode": false}To do a live end-to-end check, type a message with a throwaway/example key in chat and watch the original get blocked and a sanitized version come back. For the most realistic test, use a real-format-but-dead token. More standalone diagnostics (including how to run the orchestrator) are in Troubleshooting.
Keyward is two layers, and they have different requirements:
-
Detect + save + sanitize (
detect.py+intercept.py) — pure Python stdlib. Works on every platform, including SSH, headless, Docker, and unsupported Wayland compositors. If this layer runs, your secret is saved to~/.claude/secrets/<name>.txt(chmod 600) and the raw value is kept out of the blocked prompt. -
Auto-paste (
automate_paste.py) — needs the OS clipboard/keystroke tools and a display server. This is the layer that's platform-sensitive (macOS Accessibility, X11 tools, Wayland compositor support, Windows SendKeys policy).
So "Keyward saved my key but didn't paste the clean prompt" is a layer-2 condition, not a broken install — the security part worked, only the convenience automation didn't. The sanitized text is on your clipboard; paste it with Cmd/Ctrl+V + Enter, or set KEYWARD_DISABLE_PASTE=1 to make manual-paste the explicit default. Diagnosing why layer 2 didn't fire is covered in Troubleshooting.
Marketplace install:
/plugin marketplace update keyward
then restart Claude Code.
Manual (symlinked) install — pull the clone; the symlink picks it up:
git -C ~/keyward pullRestart Claude Code so the reloaded hook is registered.
Manual (copied) install — re-copy over the old directory, then restart:
# macOS / Linux
git -C ~/keyward pull
rm -rf ~/.claude/plugins/keyward
cp -R ~/keyward ~/.claude/plugins/keyward# Windows (copied install)
git -C "$env:USERPROFILE\keyward" pull
Remove-Item -Recurse -Force "$env:USERPROFILE\.claude\plugins\keyward"
Copy-Item -Recurse "$env:USERPROFILE\keyward" "$env:USERPROFILE\.claude\plugins\keyward"1. Remove the plugin from Claude Code.
Marketplace install:
/plugin uninstall keyward@keyward
Manual install — delete the symlink or copied directory:
# macOS / Linux
rm ~/.claude/plugins/keyward # symlink: removes only the link, not your clone
# if you copied instead of symlinking:
rm -rf ~/.claude/plugins/keyward# Windows
Remove-Item "$env:USERPROFILE\.claude\plugins\keyward" # symlink
Remove-Item -Recurse -Force "$env:USERPROFILE\.claude\plugins\keyward" # copied2. Restart Claude Code and confirm with /hooks that the UserPromptSubmit → intercept.py entry is gone.
3. (Optional) Remove saved secrets and logs. Uninstalling the plugin does not delete your vault. To wipe it:
# macOS / Linux — review first, then remove
ls -la ~/.claude/secrets/
rm -rf ~/.claude/secrets/# Windows
Get-ChildItem "$env:USERPROFILE\.claude\secrets"
Remove-Item -Recurse -Force "$env:USERPROFILE\.claude\secrets"This also removes the error log at ~/.claude/secrets/.last-error. Prefer per-slot deletion? Use /key-rm <name> while the plugin is still installed (it zero-overwrites before unlinking — best-effort, not guaranteed on SSD/COW filesystems; see Security-Model).
4. (Optional) Remove the clone and any env var. Delete ~/keyward if you cloned manually, and remove any KEYWARD_DISABLE_PASTE / KEYWARD_USE_GITLEAKS lines you added to your shell rc.
5. (Optional) Revoke the macOS Accessibility grant for your terminal app in System Settings → Privacy & Security → Accessibility if you added it only for Keyward.
Getting started
Reference
Project