bwx
Unofficial Bitwarden CLI with a persistent
background agent — commands don't re-prompt for the master password on
every use, similar to ssh-agent.
This fork adds first-class macOS support: Touch ID unlock, native password dialogs, SSH commit signing, and a one-shot setup command. On Linux/BSD it's a drop-in replacement for upstream bwx.
Features
- Persistent agent. Vault keys live in memory until
lock_timeoutof inactivity. - Touch ID unlock (macOS). Enroll once, and biometry replaces the master password. The password is only re-entered at enrollment time or when biometry is invalidated.
- Per-operation biometric gate. Optionally require Touch ID before
each vault read or SSH sign, with one prompt per
bwx <command>. - Native macOS prompts. Master password + 2FA code entry render as system Aqua dialogs; pinentry isn't required.
- SSH agent built in. Serve vault-stored SSH keys, including git
commit/tag signing via
gpg.format = ssh. - GUI-app integration.
bwx setup-macoswiresSSH_AUTH_SOCKinto launchd so IntelliJ, GitHub Desktop, Finder-launched tools, etc. see the agent without per-app config.
Install
macOS
&&
Everywhere else
| Channel | Command |
|---|---|
| Homebrew (macOS / Linux) | brew install DrewCarlson/tap/bwx-cli |
| crates.io (any platform) | cargo install --locked bwx-cli (binaries are bwx / bwx-agent) |
| Arch (AUR — release) | yay -S bwx-cli (or any AUR helper) |
| Arch (AUR — git) | yay -S bwx-cli-git |
| Nix flake | nix profile install github:drewcarlson/bwx-cli |
Debian / Ubuntu (.deb) |
download from GitHub Releases → sudo dpkg -i bwx-cli_*_amd64.deb |
Fedora / RHEL (.rpm) |
download from GitHub Releases → sudo dnf install ./bwx-cli-*.x86_64.rpm |
| Standalone tarball | download from GitHub Releases, extract, put bwx/bwx-agent on PATH |
Each tagged release builds Linux x86_64 + aarch64 (glibc and musl)
and macOS arm64 + x86_64 artifacts, attached to the GitHub Release.
On Linux you'll also want pinentry from your distro so the
master-password prompt has a UI.
Verifying release artifacts
Every artifact carries a SLSA build-provenance attestation (signed
with the release workflow's GitHub OIDC identity, recorded in the
sigstore rekor transparency log) plus, when the maintainer's minisign
secret is configured, a .minisig backup.
# GitHub-native attestation verify. Confirms the artifact was built
# by the bwx-cli release workflow on a tagged commit; no local key
# to install. Requires the `gh` CLI.
# Minisign — single shipped pubkey at packaging/minisign.pub.
# `SHA256SUMS` covers every file in the release; verify it once,
# then check artifacts against it.
Usage
# --raw for JSON
Commands auto-unlock and auto-login as needed. bwx get accepts a
name, UUID, or URL.
Bitwarden.com users: run bwx register once with your
personal API key
before bwx login. The official server's bot detection rejects CLI
clients that haven't registered.
Touch ID unlock (macOS)
Enroll once:
After enrollment Touch ID alone unlocks the vault. The master password
is needed again only if you bwx touchid disable, change your
enrolled fingerprint set, or re-authenticate with the server.
Optionally prompt Touch ID on each sensitive operation:
Prompts are coalesced: one bwx <command> triggers one Touch ID
dialog regardless of how many internal decrypts it performs.
SSH agent & git commit signing
bwx-agent exposes an SSH agent that serves SSH keys stored in your vault. Store an "SSH Key" item, then:
# Configured automatically by `bwx setup-macos`; explicit equivalent:
Git commit signing via gpg.format = ssh:
# Optional, for `git log --show-signature`:
Add a confirmation prompt before each signature (defence in depth against a process silently signing while the agent is unlocked):
GUI git clients (IntelliJ, GitHub Desktop) only see
SSH_AUTH_SOCK from launchd's environment, which is what
bwx setup-macos populates. After running it, Cmd-Q any already-open
editor and relaunch — they only pick up the new env on launch.
IntelliJ IDEs specifically: Settings → Version Control → Git →
"Native" (not Built-in). JGit doesn't honor gpg.format = ssh.
Configuration
| Key | Default | |
|---|---|---|
email |
— | Required. |
base_url |
https://api.bitwarden.com |
Self-hosted server URL. |
lock_timeout |
3600 |
Seconds idle → re-lock. |
sync_interval |
3600 |
Seconds between auto-syncs. 0 disables. |
touchid_gate |
off |
off / signing / all. |
macos_unlock_dialog |
true (macOS) |
Native dialog vs. pinentry. |
ssh_confirm_sign |
false |
Pinentry CONFIRM before each SSH sign. |
pinentry |
pinentry |
Pinentry binary to use. |
Profiles
Set BWX_PROFILE=<name> to keep an independent vault, config, and
agent under that name.
2FA
Supported: Email, Authenticator App, Yubico OTP security key.
Not supported: WebAuthn / Passkey, Duo. Add a supported mechanism alongside them — bwx will use the supported one while your web/mobile clients keep whichever you prefer.
Appendix: macOS internals
Code signing
cargo install produces unsigned binaries; macOS AMFI kills unsigned
processes that touch the Keychain. scripts/install.sh wraps
cargo install and runs scripts/sign-macos.sh, which auto-picks the
strongest signing identity on your machine:
$IDENTITYenv var (explicit override).- Developer ID Application cert (paid Apple Developer program).
- Apple Development cert (free via Xcode).
- Ad-hoc.
Keychain security varies by tier:
| Identity | Keychain item ACL |
|---|---|
| Developer ID Application | OS-enforced biometric ACL — strongest. |
| Apple Development | Plain item; Touch ID enforced by bwx-agent only. |
| Ad-hoc | Same as Apple Development. |
Only Developer ID Application carries keychain-access-groups on a
CLI binary; the other tiers would need a provisioning profile, which
bare binaries can't have. The runtime detects which entitlements the
installed binary actually holds and branches automatically — the same
source builds all three tiers. Upgrading tiers later: re-run
./scripts/install.sh, then bwx touchid disable && bwx touchid enroll
to migrate the Keychain item.
bwx setup-macos
Installs two LaunchAgents under ~/Library/LaunchAgents/:
drews.website.bwx.ssh-auth-sock— runs~/bin/bwx-set-ssh-sockat login, which callslaunchctl setenv SSH_AUTH_SOCK $(bwx ssh-socket). Puts the socket into launchd's environment so GUI apps inherit it.drews.website.bwx.agent— runsbwx-agent --no-daemonizeunder launchd supervision withKeepAlive. Log output lands in~/Library/Application Support/bwx/launchd-agent.{out,err}.
bwx teardown-macos unloads both and removes the files.