Bitwarden CLI — Secrets Management
Core Concept
Secrets are stored as Bitwarden Secure Notes with export KEY='value' lines in the notes field.
One eval call loads them into the current shell. No files on disk. Secrets die with the session.
Shell Functions
All functions ship in lib/bw-functions.sh — source it in your shell profile. No copy-pasting, no dotfiles dependency.
Setup on a new machine
# 1. Install bw CLI
brew install bitwarden-cli # macOS
sudo snap install bw # Ubuntu
npm i -g @bitwarden/cli # any OS
# 2. Install skill (choose one)
npx clawhub install bitwarden-bwe # via ClawHub
# or: git clone https://github.com/stevengonsalvez/clawdbot /path/to/clawdbot
# 3. Source functions in your shell profile
echo 'source /path/to/skills/bitwarden-bwe/lib/bw-functions.sh' >> ~/.bashrc
source ~/.bashrc
# 4. Login + unlock
export BW_CLIENTID="user.xxxxx"
export BW_CLIENTSECRET="xxxxx"
bw login --apikey
bwss # unlock (prompts for master password)
# 5. Verify
bwl # list vault items
What's in lib/bw-functions.sh
| Function | Purpose |
|---|---|
bwss | Unlock vault, set BW_SESSION interactively |
bwe <name> | Load secrets from Secure Note into env via eval |
bwe_safe <name> | Same, but only evals lines matching export VAR=value — defence-in-depth for shared orgs |
bwc <name> [file] | Create Secure Note from .env file (auto-quotes values, uses mktemp + chmod 600) |
bwce <name> | Create Secure Note from current shell exports |
bwdd <name> | Delete item by name |
bwl | Alias: list all item names |
bwll <grep> | Alias: search item names |
bwg <name> | Alias: get full item JSON |
Notes on bwe_safe: Guards against non-export lines being injected but does not sanitize values — a value containing $(cmd) or backticks would still execute during eval. If someone has write access to your Bitwarden vault, you have bigger problems. Use on shared org accounts as a defence-in-depth layer.
References
lib/bw-functions.sh— sourceable shell functions (the canonical implementation)references/cli-reference.md— Bitwarden CLI install, auth, and common operations
Workflow
Daily use
bwss # Unlock vault (once per terminal session)
bw sync # Pull latest from server (if secrets were updated in web vault)
bwe agent-fleet # Load all agent secrets
echo $ANTHROPIC_API_KEY # Verify — should be set
Creating / updating secrets
# From a .env file
bwc my-new-project .env
# From current shell
bwce snapshot-2026-03-03
# Update an existing note (delete + recreate)
bwdd old-note
bwc old-note .env.updated
# Or edit in web vault — notes field, one `export KEY='value'` per line
Org + Collection pattern (team/fleet use)
For sharing secrets with a machine account (e.g., GCP VM):
- Create a Bitwarden Organization (free tier = 2 users)
- Create a Collection in the org (e.g.,
popa-secrets) - Create a machine account — separate Bitwarden account, invited to org, assigned to the collection
- Add Secure Notes to the collection with
export KEY='value'format - On the target machine: install skill, source
lib/bw-functions.sh, login with machine account API key,bwss,bwe <note>
The machine account sees ONLY items in its assigned collection. Revoke access = remove from org. One click.
Creating items in a collection (programmatic)
COLLECTION_ID="<collection-uuid>"
ORG_ID="<org-uuid>"
NOTES=$(cat .env | awk '{print "export " $0}')
bw get template item | jq \
--arg notes "$NOTES" \
--arg name "my-item" \
--arg orgId "$ORG_ID" \
--argjson colIds "[\"$COLLECTION_ID\"]" \
'.type = 2 | .secureNote.type = 0 | .notes = $notes | .name = $name | .organizationId = $orgId | .collectionIds = $colIds' \
| bw encode | bw create item
Listing collections and orgs
bw list organizations | jq '.[] | {id, name}'
bw list collections | jq '.[] | {id, name}'
bw list items --collectionid <id> | jq '.[] | .name'
Secure Note Format
Each Secure Note's notes field contains one secret per line:
export ANTHROPIC_API_KEY='sk-ant-...'
export OPENAI_API_KEY='sk-proj-...'
export DISCORD_TOKEN='MTQ3...'
Rules:
- One
export KEY='value'per line - Always single-quote values. Unquoted values containing
|,!,#,$, backticks, or other shell metacharacters will break or execute duringeval. Single quotes prevent this. - No comments, no blank lines (they get eval'd)
- Keys should be
UPPER_SNAKE_CASE - If a value itself contains a single quote, use
'\''to escape it:export KEY='value'\''s edge case' - Never put shell commands in values
Guardrails
- Never paste secrets into chat, logs, or code. Use
bweto load into memory only. - Never write secrets to disk unless absolutely necessary (and chmod 600 if you must).
- Prefer
bweover~/.secrets/files. Secrets in memory > secrets on disk. - Use
bwe_safeon shared/org accounts. Defence in depth against note tampering. bwssonce per terminal session. The session token persists until the shell exits.- Sync before pulling:
bw syncif you've recently updated secrets in the web vault. - Lock when done:
bw lockto clear the session token.
Tmux Considerations
If using bw inside tmux (common for agents), the BW_SESSION env var must be available in the tmux pane. Either:
- Run
bwssinside the tmux pane, or - Export
BW_SESSIONbefore creating the tmux session
# Option 1: unlock inside tmux (preferred — interactive, no password in process list)
tmux new-session -d -s work
tmux send-keys -t work 'bwss' Enter
# ... wait for unlock prompt, enter master password ...
tmux send-keys -t work 'bwe agent-fleet' Enter
# Option 2: pass session token via env var (non-interactive)
# ⚠️ Never pass the master password as a CLI argument — it's visible in `ps aux`.
# Use --passwordenv instead:
read -s BW_MASTER_PASSWORD && export BW_MASTER_PASSWORD
export BW_SESSION=$(bw unlock --passwordenv BW_MASTER_PASSWORD --raw)
unset BW_MASTER_PASSWORD
tmux new-session -d -s work -e "BW_SESSION=$BW_SESSION"
tmux send-keys -t work 'bwe agent-fleet' Enter
Quick Reference
| Command | What it does |
|---|---|
bwss | Unlock vault, set BW_SESSION |
bwe <name> | Load secrets from note into env |
bwe_safe <name> | Same, with input validation |
bwc <name> [file] | Create note from .env file |
bwce <name> | Create note from current exports |
bwdd <name> | Delete item by name |
bwl | List all item names |
bwll <grep> | Search item names |
bwg <name> | Get full item JSON |
bw sync | Pull latest from server |
bw lock | Clear session token |