VW Keystroke
Paste a secret once — it lands in your Vaultwarden/Bitwarden vault and a local 600 env file, in one move.
Built for the "hot potato" moment: you just generated an API key and you want it off your clipboard and safely stored without a five-step ritual — so it doesn't end up lingering in a scratch file. Name it, paste it, done.
- 🗄️ Saves to your vault as a Login item (username = the env var, password = the value, with the env-file path recorded as a custom field).
- 📄 Writes
~/.config/<project>.env(chmod 600, updated in place — never duplicated). - 🔒 Zero-knowledge: your master password never leaves your machine; all vault crypto is done by the official
bwCLI. - ⚡ Caches the unlocked session in your OS keyring (Windows Credential Locker / macOS Keychain / Linux libsecret) so daily use needs no password.
- 🖥️ GUI and CLI, on Windows / Linux / macOS.
- 🔁 Full lifecycle:
drop·status·pull·rotate·revoke— capture, reconcile, rebuild env files from the vault, rotate a value everywhere, or purge a secret from everywhere (env file, vault, shell history, clipboard). - 🔌 Pluggable backends: Vaultwarden/Bitwarden (default), KeePassXC (offline
.kdbx), 1Password, HashiCorp Vault/OpenBao — oneBACKEND=line switches the store.
The secret value is never passed on the command line and never echoed — only the
600env file and your vault ever see it.
Requirements
- Bitwarden CLI —
npm install -g @bitwarden/cli(providesbw). - Python 3.9+ (Tkinter ships with the standard python.org installers).
Install
pipx install vw-keystroke # recommended
# or
pip install --user vw-keystroke
# or straight from source:
pipx install git+https://github.com/PolyDevHouse/vw-keystroke
This gives you three commands: vwks (CLI), keydrop (alias), and vwks-gui (GUI).
First-time setup
# point bw at your server (self-hosted Vaultwarden, or Bitwarden cloud)
bw config server https://vault.example.com
bw login # email + master password + 2FA (once)
# optional config
mkdir -p ~/.config
cp vw-keystroke.conf.example ~/.config/vw-keystroke.conf && chmod 600 ~/.config/vw-keystroke.conf
Backends
Store secrets in the vault of your choice — pick one with BACKEND= in your config:
| Backend | BACKEND= |
Install | Notes |
|---|---|---|---|
| Vaultwarden / Bitwarden (default) | bitwarden |
needs the bw CLI |
self-hosted or cloud |
| KeePassXC | keepass |
pipx install "vw-keystroke[keepass]" |
offline single .kdbx — ideal on a USB / VeraCrypt drive, no daemon |
| 1Password | 1password |
needs the op CLI |
service-account auth |
| HashiCorp Vault / OpenBao | vault |
pipx install "vw-keystroke[vault]" |
self-hosted, KV-v2 |
Only items VW Keystroke created (marked with an env_file field) are ever listed, rotated, or revoked — your ordinary vault logins are never touched.
Use
GUI: launch VW Keystroke from your app menu (Linux .desktop in
packaging/), or run vwks-gui.
CLI — the secret lifecycle:
vwks OPENAI_API_KEY --project openai # capture (drop): -> ~/.config/openai.env + vault
echo -n "$SECRET" | vwks --var FOO --project bar # piped / non-interactive
vwks status # reconcile vault vs env files (match / drift / …)
vwks pull --project openai # rebuild the env file FROM the vault (or --all)
vwks rotate OPENAI_API_KEY --generate --exec "systemctl --user restart mybot"
vwks revoke OPENAI_API_KEY # purge from env + vault + shell history + clipboard
vwks --lock # forget the cached session + lock now
Configuration
~/.config/vw-keystroke.conf (all optional — see vw-keystroke.conf.example):
| Key | Meaning | Default |
|---|---|---|
BW_SERVER |
Vault server URL | current bw config |
DEFAULT_PROJECT |
env-file basename | keys |
VAULT_FOLDER |
folder for new items | API Keys |
KEYRING_TTL_DAYS |
cached-session lifetime (0 = never cache) |
30 |
ENV_DIR |
where env files go | ~/.config |
BW_CLIENTID / BW_CLIENTSECRET |
optional API-key login | — |
BACKEND |
vault backend: bitwarden / keepass / 1password / vault |
bitwarden |
HISTORY_FILES |
shell histories revoke scrubs |
~/.zsh_history,~/.bash_history |
KEEPASS_DB / KEEPASS_KEYFILE |
KeePass .kdbx path (+ optional keyfile) |
~/.config/vwks.kdbx |
OP_VAULT / OP_SERVICE_ACCOUNT_TOKEN |
1Password target vault + service-account token | — |
VAULT_ADDR / VAULT_TOKEN / VAULT_MOUNT |
Vault URL, token, KV mount | http://127.0.0.1:8200 / — / secret |
How it works
bw handles login and all encryption. On a drop, VW Keystroke unlocks (or reuses a
cached session), then creates/updates the vault item and the env file. If the vault
is locked it asks for your master password once; the resulting session key is stored
in your OS keyring with a TTL and refreshed on use.
Security notes
- Nothing sensitive is stored by this tool except the
600env file you asked for and the keyring session (same protection as your desktop login). - A cached session means anyone at your already-unlocked machine can drop/read keys — the same exposure as a logged-in browser vault extension. Set
KEYRING_TTL_DAYS=0to disable caching. - This project ships no credentials, servers, or keys of its own.
License
MIT © PolyDevHouse LLC
Metadata
Release files for vw-keystroke 0.3.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| vw_keystroke-0.3.0.tar.gz | 38.1 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| vw_keystroke-0.3.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 77.0 kB
Release files / vw_keystroke-0.3.0.tar.gz
| Download URL | vw_keystroke-0.3.0.tar.gz |
|---|---|
| Size | 38.1 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
a02f707961ef810c5ba6554fb5e0285d203dc39b7c9664b1e92a3a03e4908258
|
|
BLAKE2b-256 checksum How to use checksums |
eae827a5fbfcd8d0fc900df3af432ee62a7a4fdb93c67acc6d0ac12cd49ce50f
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.14.7
|
Release files / vw_keystroke-0.3.0-py3-none-any.whl
| Download URL | vw_keystroke-0.3.0-py3-none-any.whl |
|---|---|
| Size | 38.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
9067fa90994ba1c4d5cb7c9e6bf863f85b79f03a197c1f62e706a7d68eca81a6
|
|
BLAKE2b-256 checksum How to use checksums |
52bc45252f1cd35861f2053d7fdcb97e45e478dfae385175774c76ee340d8ce7
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.14.7
|