Keychain Manager
Store, retrieve, list, rotate, and delete secrets in the macOS Keychain via the security CLI.
When to Trigger
- User asks to store a secret, API key, or token
- User asks to retrieve a credential from the keychain
- User wants to manage, rotate, or delete stored keys
- User asks "add to keychain" or "get from keychain"
- A workflow requires a secret that should not be hardcoded
Naming Convention
All entries use a consistent format:
- Account:
bbmisa(always-a bbmisa) - Service: UPPERCASE_WITH_UNDERSCORES (e.g.,
GITHUB_PERSONAL_ACCESS_TOKEN)
This ensures secrets are easily discoverable and follow a predictable pattern.
Operations
Store a Secret
security add-generic-password -a bbmisa -s SERVICE_NAME -w "token_value"
To update an existing entry (overwrite):
security add-generic-password -a bbmisa -s SERVICE_NAME -w "new_token_value" -U
The -U flag updates the password if the entry already exists.
Retrieve a Secret
security find-generic-password -a bbmisa -s SERVICE_NAME -w
Returns only the password value to stdout. Use in scripts:
TOKEN=$(security find-generic-password -a bbmisa -s SERVICE_NAME -w 2>/dev/null)
List Stored Secrets
Search by pattern:
security dump-keychain | grep "svce" | grep -i "pattern"
List all Berna-managed secrets:
security dump-keychain | grep -A4 '"acct"<blob>="bbmisa"' | grep "svce"
Delete a Secret
security delete-generic-password -a bbmisa -s SERVICE_NAME
Rotate a Secret
Follow this sequence — never delete before verifying the new value:
- Retrieve the old value (for rollback if needed)
- Store the new value with
-U - Verify retrieval returns the new value
- Confirm with the user
# Step 1: Note old value exists
security find-generic-password -a bbmisa -s SERVICE_NAME -w > /dev/null 2>&1 && echo "Old value exists"
# Step 2: Update with new value
security add-generic-password -a bbmisa -s SERVICE_NAME -w "new_token_value" -U
# Step 3: Verify
security find-generic-password -a bbmisa -s SERVICE_NAME -w
Shell Integration
Add to ~/.zshrc for automatic environment variable export:
export GITHUB_TOKEN="$(security find-generic-password -a bbmisa -s GITHUB_PERSONAL_ACCESS_TOKEN -w 2>/dev/null)"
export HUGGINGFACE_TOKEN="$(security find-generic-password -a bbmisa -s HUGGINGFACE_TOKEN -w 2>/dev/null)"
export FIRECRAWL_API_KEY="$(security find-generic-password -a bbmisa -s FIRECRAWL_API_KEY -w 2>/dev/null)"
The 2>/dev/null suppresses errors if the key does not exist, preventing shell startup noise.
Known Tokens in Keychain
These tokens are already stored and available:
| Service Name | Used For |
|---|---|
HUGGINGFACE_TOKEN |
HuggingFace Inference API |
FIRECRAWL_API_KEY |
Firecrawl web scraping |
MEM0_API_KEY |
Mem0 persistent AI memory |
DAYTONA_API_KEY |
Daytona dev environments |
GITHUB_PERSONAL_ACCESS_TOKEN |
GitHub API and CLI auth |
Anti-Patterns
Never do these:
- Echo tokens to stdout unmasked — if displaying for verification, show only first 4 and last 4 characters
- Store in plaintext files — no
.envfiles with real values committed to git; use.env.examplewith placeholders - Commit keychain retrieval output — never let
security find-generic-passwordoutput end up in git history - Use short or ambiguous service names — always use descriptive uppercase names (e.g.,
STRIPE_LIVE_SECRET_KEYnotstripe) - Skip the
-a bbmisaflag — without it, entries are harder to find and may collide with system entries
Masked Display Helper
When the user asks to verify a stored secret, display it masked:
TOKEN=$(security find-generic-password -a bbmisa -s SERVICE_NAME -w 2>/dev/null)
echo "${TOKEN:0:4}****${TOKEN: -4}"
This shows ghp_****Ab1x — enough to confirm identity without exposing the full value.