🔐 1Password shell plugins¶
1Password shell plugins let a CLI authenticate with your fingerprint
instead of a long-lived token sitting in a plaintext config file. Running
gh, for example, prompts 1Password for approval and injects the credential
into that single command's environment — nothing is written to disk.
Why this repo defines the wrappers itself¶
By default op plugin init writes shell functions to
~/.config/op/plugins.sh and manages that file for you. That file is outside
version control, so a new machine silently loses the configuration.
1Password documents an alternative: define the wrapper functions yourself and track them in your dotfiles. That is what this repo does.
op plugin init default |
This repo | |
|---|---|---|
| Wrapper location | ~/.config/op/plugins.sh |
~/.config/shell/functions/op-plugins.sh, ~/.config/fish/conf.d/op-plugins.fish |
| Tracked in git | ❌ | ✅ (generated from chezmoi templates) |
| New machine | re-run op plugin init per CLI |
wrappers apply with chezmoi apply |
OP_PLUGIN_ALIASES_SOURCED=1 is exported alongside the wrappers, which tells
1Password CLI the aliases are already set up so it stops asking you to source
plugins.sh.
Which CLIs are wrapped¶
The list comes from the chezmoi opShellPlugins variable and defaults to:
gh— GitHub CLIcopilot— GitHub Copilot CLI, which the plugin authenticates with aCOPILOT_GITHUB_TOKEN
Override it per machine in your local chezmoi config, as a list:
or as a comma-separated string (trimmed, de-duplicated and sorted for you):
Then re-run chezmoi apply. Run op plugin list to see the 60+ supported
CLIs.
First-time setup per CLI¶
The wrappers only decide how a CLI is invoked. You still tell 1Password which item holds the credential, once per CLI and machine:
You will be asked to import a new item or pick an existing one, then choose when the credential applies (this terminal session, this directory tree, or globally).
Useful follow-ups:
op plugin inspect gh # show configured credentials and scopes
op plugin clear gh # reset the credential defaults
After importing a credential into 1Password, delete any plaintext copy that is
still lying around (for example ~/.config/gh/hosts.yml).
Safety rails¶
The generated wrappers are deliberately defensive, because a wrapper that cannot run would otherwise replace a working CLI:
- No
op, no wrappers. If the 1Password CLI is not onPATH, nothing is defined at all and every CLI behaves normally. - Only installed CLIs are wrapped. Defining a
ghfunction on a machine withoutghwould makecommand -v ghsucceed and break the usual "is it installed?" checks, so each wrapper is guarded on the real CLI existing. - Completions keep working. The fish wrappers use
--wraps, and the bash/zsh completion files load before the wrappers, so generating completions never triggers a 1Password prompt at shell startup. - Not in SSH sessions.
op plugin runneeds the 1Password desktop app for biometric unlock, which a headless host does not have. The wrappers are therefore guarded onSSH_CONNECTION, so they never shadow a CLI on a server — see below.
Interaction with copilot-ssh¶
copilot-ssh forwards COPILOT_GITHUB_TOKEN (and
optionally GH_TOKEN) to a headless server over SSH, precisely because that
server has no vault to unlock. A plugin wrapper on the remote side would
hijack copilot / gh and route them through op plugin run, which cannot
work there — breaking the forwarded-token flow.
The SSH_CONNECTION guard prevents this: inside a copilot-ssh session the
real binaries run and pick up the forwarded tokens, while on your workstation
the plugin still authenticates you with biometrics.
WSL is not supported¶
op plugin run refuses to run under WSL — you get "Shell Plugins are
currently not supported on this operating system" (tracked upstream in
1Password/shell-plugins#402). Wrapping a CLI with a command that
always fails is worse than not wrapping it, so chezmoi skips both wrapper
files on WSL hosts via .chezmoiignore.
WSL still reaches 1Password for SSH and Git signing through the Windows host — see wsl.md.