Summary
Migrate all API keys and secrets from the iCloud-stored .env file to 1Password for improved security, audit trails, and centralized secret management.
Current State
Secrets stored in: ~/Library/Mobile Documents/com~apple~CloudDocs/Geoffrey/secrets/.env
9 secrets identified across 4 skills:
| Secret |
Used By |
FRESHSERVICE_DOMAIN |
freshservice-manager (10 scripts) |
FRESHSERVICE_API_KEY |
freshservice-manager (10 scripts) |
PERPLEXITY_API_KEY |
research, multi-model-research |
GEMINI_API_KEY |
research, multi-model-research, image-gen (3 scripts) |
OPENAI_API_KEY |
research, multi-model-research |
XAI_API_KEY |
multi-model-research |
GOOGLE_CLIENT_ID |
google-workspace |
GOOGLE_CLIENT_SECRET |
google-workspace |
ELEVENLABS_API_KEY |
elevenlabs-tts (2 scripts) |
OBSIDIAN_API_KEY |
MCP server (external) |
Current security concerns:
- Plain text file on iCloud (synced to cloud)
- No access audit trail
- No rotation management
- All-or-nothing access (no granular permissions)
Proposed Solution
Use 1Password CLI (op) with secret references to load secrets at runtime.
Secret Reference Format
op://Geoffrey/Freshservice/api-key
op://Geoffrey/OpenAI/api-key
Implementation Patterns
Pattern A: Wrapper script (Recommended)
Create scripts/load-secrets.sh:
#!/bin/bash
export FRESHSERVICE_API_KEY="op://Geoffrey/Freshservice/api-key"
export OPENAI_API_KEY="op://Geoffrey/OpenAI/api-key"
# ... etc
op run -- "$@"
Scripts call: ./load-secrets.sh bun myscript.js
Pattern B: Per-script integration
Each script loads its own secrets:
const { execSync } = require('child_process');
const apiKey = execSync('op read "op://Geoffrey/Freshservice/api-key"').toString().trim();
Pattern C: Template .env with op inject
Create .env.tpl:
FRESHSERVICE_API_KEY={{ op://Geoffrey/Freshservice/api-key }}
Generate at runtime: op inject -i .env.tpl -o .env
Requirements
Prerequisites
1Password Vault Structure
Create items in "Geoffrey" vault:
Geoffrey/
├── Freshservice
│ ├── domain: psd401.freshservice.com
│ └── api-key: ***
├── OpenAI
│ └── api-key: ***
├── Perplexity
│ └── api-key: ***
├── Gemini
│ └── api-key: ***
├── XAI
│ └── api-key: ***
├── Google-Workspace
│ ├── client-id: ***
│ └── client-secret: ***
├── ElevenLabs
│ └── api-key: ***
└── Obsidian-MCP
└── api-key: ***
Acceptance Criteria
Implementation Plan
Phase 1: Setup (Prerequisites)
- Install 1Password CLI
- Create Geoffrey vault
- Add all 9 secrets to vault
Phase 2: Create Helper (Central Loader)
- Create
scripts/op-run.sh wrapper
- Add fallback for missing
op command (error message)
Phase 3: Update Scripts (Skill by Skill)
freshservice-manager (10 scripts):
add_note.js, create_ticket.js, get_agent.js, get_approvals.js
get_daily_summary.js, get_service_request.js, get_ticket.js
get_weekly_summary.js, get_workspaces.js, list_agents.js
list_tickets.js, search_tickets.js, update_ticket.js
research (orchestrator.js, agent .md files)
multi-model-research (llm_client.py)
image-gen (compose.py, edit.py, generate.py)
elevenlabs-tts (generate_audio.py, list_voices.py)
google-workspace (oauth_setup.js, token_manager.js)
Phase 4: Documentation
- Update CLAUDE.md secret references
- Update each skill's SKILL.md
- Remove old .env file
Technical Considerations
Backward Compatibility
- Keep checking for .env as fallback during transition
- Clear deprecation warnings if .env found
Performance
op read adds ~100-200ms per secret fetch
- Consider caching for scripts with multiple secrets
op run loads all secrets once upfront (preferred)
Error Handling
- Detect missing
op CLI with clear error message
- Detect locked 1Password with unlock prompt
- Graceful degradation if secrets unavailable
Testing Plan
- Verify each skill works with 1Password secrets
- Test on fresh machine without .env file
- Test error messages when 1Password locked/missing
References
Summary
Migrate all API keys and secrets from the iCloud-stored
.envfile to 1Password for improved security, audit trails, and centralized secret management.Current State
Secrets stored in:
~/Library/Mobile Documents/com~apple~CloudDocs/Geoffrey/secrets/.env9 secrets identified across 4 skills:
FRESHSERVICE_DOMAINFRESHSERVICE_API_KEYPERPLEXITY_API_KEYGEMINI_API_KEYOPENAI_API_KEYXAI_API_KEYGOOGLE_CLIENT_IDGOOGLE_CLIENT_SECRETELEVENLABS_API_KEYOBSIDIAN_API_KEYCurrent security concerns:
Proposed Solution
Use 1Password CLI (
op) with secret references to load secrets at runtime.Secret Reference Format
Implementation Patterns
Pattern A: Wrapper script (Recommended)
Create
scripts/load-secrets.sh:Scripts call:
./load-secrets.sh bun myscript.jsPattern B: Per-script integration
Each script loads its own secrets:
Pattern C: Template .env with op inject
Create
.env.tpl:Generate at runtime:
op inject -i .env.tpl -o .envRequirements
Prerequisites
brew install --cask 1password-cli1Password Vault Structure
Create items in "Geoffrey" vault:
Acceptance Criteria
Implementation Plan
Phase 1: Setup (Prerequisites)
Phase 2: Create Helper (Central Loader)
scripts/op-run.shwrapperopcommand (error message)Phase 3: Update Scripts (Skill by Skill)
freshservice-manager (10 scripts):
add_note.js,create_ticket.js,get_agent.js,get_approvals.jsget_daily_summary.js,get_service_request.js,get_ticket.jsget_weekly_summary.js,get_workspaces.js,list_agents.jslist_tickets.js,search_tickets.js,update_ticket.jsresearch (orchestrator.js, agent .md files)
multi-model-research (llm_client.py)
image-gen (compose.py, edit.py, generate.py)
elevenlabs-tts (generate_audio.py, list_voices.py)
google-workspace (oauth_setup.js, token_manager.js)
Phase 4: Documentation
Technical Considerations
Backward Compatibility
Performance
op readadds ~100-200ms per secret fetchop runloads all secrets once upfront (preferred)Error Handling
opCLI with clear error messageTesting Plan
References