Vault¶
What Is the Vault?¶
The vault is an encrypted credential store that lets Claude Code manage secrets (API keys, tokens, passwords) without ever writing them to disk in plaintext. Under the hood, it is a JSON object encrypted with age, a modern file encryption tool.
Credentials are stored in a single encrypted file at ~/.claude-superpowers/vault.enc. They can be injected into skill environments at runtime, keeping secrets out of .env files, shell history, and logs.
How age Encryption Works¶
age is a simple, modern encryption tool that uses X25519 key pairs.
age-keygengenerates an identity file containing a private key and its corresponding public key- Encryption uses the public key -- anyone with it can encrypt data, but only the private key holder can decrypt
- Decryption requires the identity file (private key)
The vault uses age as a subprocess:
- Encrypt:
echo '{"key":"value"}' | age -r <public-key> > vault.enc - Decrypt:
age -d -i age-identity.txt < vault.enc
No age library is linked -- the age and age-keygen CLI binaries must be installed on the system.
Initial Setup¶
Prerequisites¶
Install age on Debian/Ubuntu:
On macOS:
Initialize the Vault¶
This does three things:
- Generates an age keypair at
~/.claude-superpowers/age-identity.txt(chmod 600) - Creates an empty encrypted vault at
~/.claude-superpowers/vault.enc(chmod 600) - Optionally stores the identity file path in macOS Keychain (macOS only) under the service
claude-superpowers-vault
Output:
Vault initialized.
Identity: /home/you/.claude-superpowers/age-identity.txt
Vault: /home/you/.claude-superpowers/vault.enc
Public key: age1ql3z7hjy54pw3hyww5ayyfg7zqgvc7w3j2elw8zmrj2kg5sfn9aqmcac8p
If an identity file already exists, init skips key generation and reuses the existing key.
Storing and Retrieving Credentials¶
Store a Secret¶
claw vault set ANTHROPIC_API_KEY sk-ant-abc123...
claw vault set SLACK_BOT_TOKEN xoxb-...
claw vault set DB_PASSWORD hunter2
Each set decrypts the vault, adds/updates the key, and re-encrypts.
Retrieve a Secret¶
By default, values are masked:
Use --reveal to show the full value:
List All Keys¶
$ claw vault list
Vault Keys
┌────┬────────────────────┐
│ # │ Key │
├────┼────────────────────┤
│ 1 │ ANTHROPIC_API_KEY │
│ 2 │ DB_PASSWORD │
│ 3 │ SLACK_BOT_TOKEN │
└────┴────────────────────┘
Keys are sorted alphabetically. Values are never shown in the list view.
Delete a Secret¶
Raises an error if the key does not exist.
Optional macOS Keychain Integration¶
On macOS, claw vault init stores the identity file path in the system Keychain:
- Service:
claude-superpowers-vault - Account:
age-identity - Password: (the filesystem path to
age-identity.txt)
This is a convenience feature -- it lets future phases locate the identity file without hardcoded paths. The Keychain entry stores the path to the key, not the key itself.
If Keychain access fails (non-macOS, permissions denied), the operation is silently skipped. The vault works fine without it.
Security Model¶
Encryption at Rest¶
- All secrets are stored in a single age-encrypted file (
vault.enc) - The vault is never written to disk in plaintext
- The identity file (private key) is created with
chmod 600 - The vault file is written with
chmod 600
Atomic Writes¶
Every write operation (set, delete) follows this pattern:
- Decrypt the vault into memory
- Modify the in-memory dictionary
- Re-encrypt to a temporary file (
.vault-*.tmp) - Atomically rename the temp file to
vault.encusingos.replace()
This prevents corruption if the process is interrupted mid-write. If anything fails, the temporary file is cleaned up and the original vault is untouched.
Sandboxed Skill Execution¶
When skills are run via SkillLoader.run_sandboxed():
- Skills without
vaultpermission get a minimal environment:PATH,HOME,LANG,TERMonly - Skills with
vaultpermission receive the full environment, including any vault-injected variables - This prevents accidental secret leakage to untrusted skills
What Is NOT Protected¶
- The identity file is a plaintext age private key on disk. Anyone with filesystem access to
~/.claude-superpowers/age-identity.txtcan decrypt the vault. - The vault is only as secure as your filesystem permissions and user account.
- Secrets are briefly held in memory during decrypt/encrypt cycles.
Programmatic API¶
The Vault class can be used directly from Python:
from superpowers.vault import Vault
v = Vault()
# Initialize (only needed once)
v.init()
# CRUD operations
v.set("MY_KEY", "my-secret-value")
value = v.get("MY_KEY") # "my-secret-value"
keys = v.list_keys() # ["MY_KEY"]
v.delete("MY_KEY")
# Export for environment injection
env = v.export_env() # All keys as dict
env = v.export_env(["KEY1", "KEY2"]) # Specific keys only
Custom Paths¶
CLI Reference¶
claw vault init¶
Generate age keypair and create empty vault. Safe to run multiple times -- skips if identity already exists.
claw vault set <key> <value>¶
Store or update a credential. The key is case-sensitive.
claw vault get <key> [--reveal]¶
Retrieve a credential. Masked by default; use --reveal to show the full value.
claw vault list¶
List all stored keys in a table. Values are never displayed.
claw vault delete <key>¶
Remove a credential. Errors if the key does not exist.