Files
claudetools/.claude/skills/vault/SKILL.md
Mike Swanson 9c56690270 sync: auto-sync from GURU-5070 at 2026-06-10 20:18:48
Author: Mike Swanson
Machine: GURU-5070
Timestamp: 2026-06-10 20:18:48
2026-06-10 20:19:05 -07:00

6.7 KiB

name, description
name description
vault The ONE canonical way to use the ClaudeTools SOPS+age secret vault — read, store, update, and verify credentials. Use this whenever a task involves a password, API key, token, secret, connection string, SSH key, or any credential: retrieving one to use it, storing a newly created/discovered one, or checking what's vaulted. Stops the per-session improvising (raw sops, guessed paths, VAULT_ROOT_ENV hacks, plaintext-field mistakes). Triggers: vault, store/save a secret, add to vault, get the password/api key for X, where is the credential for X, sops, encrypt this secret, decrypt, rotate a credential, 1password fallback, vault a new key.

Vault — one consistent way to handle secrets

Vaulting should be identical every time. It is. This skill is the single source of truth so no session has to re-derive it. Two tools, one rule:

  • Reads / search / list → the canonical vault.sh (auto-resolves the vault from identity.json).
  • Create / update / verify (non-interactive)vault-helper.sh in this skill. (The base vault.sh add/edit are interactive $EDITOR flows Claude can't drive — do NOT use them; do NOT fall back to raw sops with hand-built paths.)

THE RULE (read this first)

  1. Never paste a secret into chat, a ticket, a commit message, or a coord/Discord channel. Point people at the vault path instead (teammates with vault access decrypt it themselves).
  2. Never write a secret to a field outside credentials:. The .sops.yaml only encrypts keys named credentials | password | secret | api_key | token | pre_shared_key | notes | content. A secret placed anywhere else commits in plaintext. Always put secrets under credentials:.
  3. Never hand-roll the vault path or sops command. Use the two scripts below — they resolve the vault root the same way on every machine.
  4. Finish the job: create/update → verify it's encrypted → publish (sync). Don't stop at "it's on disk, you push it."

Read a secret (canonical)

# whole entry (decrypted)
bash .claude/scripts/vault.sh get   <path>
# one field, dot-notation (e.g. credentials.api_key, credentials.admin.password)
bash .claude/scripts/vault.sh get-field <path> credentials.api_key
# find where something lives
bash .claude/scripts/vault.sh search <query>
bash .claude/scripts/vault.sh list   [subdir]

<path> is relative to the vault root, with or without the .sops.yaml suffix (e.g. clients/kittle/gururmm-site-main or msp-tools/computerguru-user-manager.sops.yaml).

The repo wrapper .claude/scripts/vault.sh reads vault_path from .claude/identity.json and delegates to the real vault.sh in the vault repo. That is the ONLY entry point you need for reads. (If vault_path is missing on a machine, fix identity.json — don't paper over it with VAULT_ROOT_ENV, which is a separate remediation-tool-script quirk, not how you read the vault.)

Store a NEW secret (non-interactive, one shot)

bash .claude/skills/vault/scripts/vault-helper.sh new <path> \
  --kind <api-key|server|m365|vpn|note|generic> \
  --name "Human-readable name" [--url https://...] [--tag client] [--tag service] \
  --set api_key=THE_SECRET [--set username=foo] [--set password=bar]

This writes the plaintext template (metadata at top level, every --set under credentials:), encrypts it in place with sops, verifies the round-trip, and tells you to publish. It refuses if the file already exists.

Update / add a field on an existing entry

bash .claude/skills/vault/scripts/vault-helper.sh set <path> --set password=NEW_VALUE

Decrypts, merges the field(s) into credentials:, re-encrypts, verifies. Use this instead of vault edit (which needs an interactive editor).

Verify (always, after any write — and before any commit)

bash .claude/skills/vault/scripts/vault-helper.sh verify <path>     # one entry: encrypted + decrypts
bash .claude/skills/vault/scripts/vault-helper.sh check [subdir]    # scan for ANY plaintext *.sops.yaml

check is the safety net against the plaintext footgun — run check over a dir (or the whole vault) before committing if you hand-edited anything.

Publish (the last mile — do it yourself)

The main sync handles the vault repo too:

bash .claude/scripts/sync.sh        # Phase 6 commits + pushes the vault repo

(Equivalent: cd <vault_path> && git add -A && git commit -m "..." && git push.) Don't park "you push it" as a task — a clean encrypted entry is routine. Only hand off if git push itself fails (auth/conflict). The Windows LF→CRLF warning on the yaml is benign — SOPS integrity is over the ENC[...] values, not line endings.

Layout & file format

Vault root subdirs: clients/<slug>/, msp-tools/, infrastructure/, services/, projects/, business/, ssh-keys/, tailscale/. Put a client credential under clients/<slug>/, an MSP app under msp-tools/, shared infra under infrastructure/ or services/.

A decrypted entry looks like:

kind: api-key                 # api-key | server | m365-tenant | vpn | note | generic
name: Human-readable name
url: https://...              # optional, plaintext metadata
status: active
tags: [client, service]       # plaintext, searchable
credentials:                  # <-- EVERYTHING secret goes here (this whole block is encrypted)
  api_key: "..."
  username: "..."
  password: "..."
notes: ""                     # encrypted too

Plaintext metadata (kind/name/url/tags/status and arbitrary non-secret structure like client: / site:) stays readable so search works. Only credentials/notes (and the other regex keys) are encrypted.

1Password fallback

The SOPS vault is primary. 1Password is the fallback when a secret isn't in SOPS or for human-shared items — use the 1password skill / op CLI for that. If you store something new and it belongs in the team flow, prefer the SOPS vault so it syncs with the repo.

Gotchas (already handled — don't re-discover them)

  • Interactive vault edit / vault add don't work in this harness ($EDITOR). Use vault-helper.sh set / new instead.
  • yq blocked on Windows (WDAC/Device Guard)vault.sh auto-falls back to a bundled Python YAML parser. Nothing to do.
  • VAULT_ROOT_ENV is only a workaround for the remediation-tool scripts mis-resolving their root; it is NOT the vault access pattern. For vault work use the two scripts here.
  • Encrypted-field regex is the one real footgun — secrets must be under credentials: (or a top-level password/api_key/token/secret/pre_shared_key/notes/content). verify catches a miss.
  • The vault repo has its own pre-commit harness-guard/hook that warns on plaintext; check is your proactive version of the same.