name: admin:refresh-secrets description: Re-inject Bitwarden secrets into ~/.secrets/ — env files (for direnv) AND arbitrary files (OAuth tokens, service-account JSON keys, etc.) for all project workspaces allowed-tools: - Bash
/admin:refresh-secrets — Refresh secrets from Bitwarden
Re-injects all bw.*.env and bw.*.files templates from ~/projects/admin/dotfiles/secrets/ into ~/.secrets/ via the Bitwarden CLI and the bw-inject / bw-files helpers.
Inputs and outputs
| Template | Output | Use case |
|---|---|---|
bw.{slug}.env |
~/.secrets/env.{slug} (export-prefixed) |
Env vars consumed by direnv + .mcp.json substitution |
bw.{slug}.files |
~/.secrets/<custom path> |
OAuth tokens, service-account JSON keys, anything not env-shaped |
Template syntax
bw.{slug}.env — one KEY=value per line:
SHOPIFY_CLIENT_ID=bw://Shopify - La Pelucherie/client_id
KLAVIYO_API_KEY=bw://Klaviyo API/password
SHOPIFY_STORE=la-pelucherie.myshopify.com
bw.{slug}.files — one <dest>=<bw://Item/field> per line:
~/.secrets/lp-seo-tracking-sa.json=bw://lp-seo-tracking-sa/notes
~/.secrets/lp-seo-oauth-token.json=bw://lp-seo-oauth-token/notes
Both formats:
- Resolve
password,username,notes,totp,urias standard fields; anything else as a custom field on the BW item. - Skip blank lines and
#comments. ~in destination paths expands to$HOME.
Steps
- Ensure Bitwarden vault is unlocked:
bw status | jq -r .status
If status is not unlocked, prompt the user to run in their terminal:
! export BW_SESSION=$(bw unlock --raw)
(The ! prefix runs the command in this Claude Code session so the BW_SESSION is available to subsequent shell calls.)
If still not unlocked after that, stop and report.
- Find all templates:
ls ~/projects/admin/dotfiles/secrets/bw.*.env ~/projects/admin/dotfiles/secrets/bw.*.files 2>/dev/null
- For each
bw.{slug}.env(env file output):
bw-inject < ~/projects/admin/dotfiles/secrets/bw.{slug}.env \
| sed 's/^/export /' > ~/.secrets/env.{slug}.new && \
mv ~/.secrets/env.{slug}.new ~/.secrets/env.{slug} && \
chmod 600 ~/.secrets/env.{slug}
(Atomic rename: if bw-inject fails mid-template, the existing env.{slug} is preserved.)
- For each
bw.{slug}.files(file output):
bw-files < ~/projects/admin/dotfiles/secrets/bw.{slug}.files
bw-files writes each resolved value directly to the destination path, atomic-replacing any existing file (chmod 600).
If bw-inject or bw-files fails for a slug: report the error, leave existing files untouched, continue with the next slug.
- Propagate to Nexus (Nexus can't self-refresh — its Bitwarden vault is locked and
bw-injectisn't on its PATH):
~/projects/admin/dotfiles/bin/secrets-sync-nexus
Pushes the freshly-resolved ~/.secrets/* files that already exist on Nexus (refresh-in-place: never adds Mac-only files, never removes Nexus-only ones like env.sporteasy). Backs up Nexus's env.* first; skips gracefully if Nexus is unreachable. This keeps Nexus in sync so a Mac refresh covers both machines.
- Summary table:
| Slug | env | files |
|---|---|---|
| perso | ✓ | — |
| rakam | ✓ | — |
| tpg | ✓ | — |
| lp | ✓ | ✓ (3 files) |
Note the Nexus propagation result (N files pushed / unreachable).
Notes
~/.secrets/*are never committed to git- After refreshing, direnv reloads automatically when you
cdinto a project that sources~/.secrets/env.{slug}from its.envrc - Env vars are also consumed at Claude Code launch via
.mcp.jsonenv var substitution - Bitwarden master password is stored in Apple Passwords (iCloud Keychain)
- For binary files (rare), prefer Bitwarden attachments + a manual retrieval step
- Legacy
op.*.envtemplates (1Password) are deprecated — migrate tobw.*.envover time