1password
git clone https://github.com/kcmadden/claude-code-1password-skill
git clone --depth=1 https://github.com/kcmadden/claude-code-1password-skill ~/.claude/skills/kcmadden-claude-code-1password-skill-1password
SKILL.md1Password Skill
⚠️ Critical: Never Type Secrets Into Claude Code
Claude Code can see everything typed in its terminal and chat.
When a user needs to store a secret, ALWAYS use the Terminal launch pattern:
- Generate a pre-filled script with known values already set
- Use
to open it in Terminal.applaunch-in-terminal.sh - User types secrets in that window — Claude Code cannot see it
- 1Password stores the secret, outputs
references back to Claudeop://
# Claude generates the script, then launches it outside its own view: bash scripts/launch-in-terminal.sh /tmp/setup-my-service.sh "Service Name Setup"
Never ask users to paste API keys, passwords, or tokens into:
- The Claude Code chat
- A Bash tool call visible in Claude Code
- Any file Claude Code writes before it's stored in 1Password
Setup Check
Always verify the CLI is ready before any operation:
bash scripts/check_setup.sh
If not installed: https://developer.1password.com/docs/cli/get-started/ If not signed in: unlock the 1Password desktop app (after Mac restart, the app must be unlocked before the CLI works)
Storing Secrets: The Terminal Launch Pattern
When a user needs to store a new secret or credential:
Step 1 — Generate the script (Claude does this, with known values pre-filled):
cat > /tmp/setup-SERVICE.sh << 'EOF' bash /path/to/store-mcp-credentials.sh \ --vault Dev \ --item "Service Name" \ --set "url=https://known-url.com" \ --set "env=production" \ --secret "api_key" \ --secret "webhook_secret" EOF
Step 2 — Launch in Terminal.app (secrets stay out of Claude Code):
bash scripts/launch-in-terminal.sh /tmp/setup-SERVICE.sh "Service Name Setup"
Step 3 — Update config (Claude uses the
op:// references from the output):
"SERVICE_API_KEY": "op://Dev/Service Name/api_key"
Core Patterns
Read a secret
op read "op://VaultName/ItemTitle/field_name" export API_KEY=$(op read "op://Dev/Anthropic/api_key")
Store a new secret
# Basic bash scripts/store_secret.sh --title "My API Key" --field api_key --value "sk-..." # With vault bash scripts/store_secret.sh --title "My API Key" --vault Dev --field api_key --value "sk-..." # From environment variable bash scripts/store_secret.sh --from-env ANTHROPIC_API_KEY --title "Anthropic" # Generate a secure credential bash scripts/store_secret.sh --title "App Secret" --field secret --generate --length 32
Update an existing secret
bash scripts/store_secret.sh --update --title "My API Key" --field api_key --value "new-value" # Or directly: op item edit "My API Key" api_key[password]=new-value
Generate a .env from 1Password
# Interactive — lists items, choose one bash scripts/env_from_op.sh # From a specific item (dry run preview) bash scripts/env_from_op.sh --item "Project Credentials" --dry-run # Write .env.tpl (secret references — safe to commit) bash scripts/env_from_op.sh --item "Project Credentials" --output .env.tpl # Write .env with resolved real values (DO NOT commit) bash scripts/env_from_op.sh --item "Project Credentials" --resolve --output .env
Secret References (op://)
The safest pattern — store
op:// references in config files instead of real values.
Privacy note:
references reveal vault names, item names, and field names. Safe to commit to private repos. For public repos, check that your vault/item naming doesn't expose sensitive structure (client names, internal service names, etc.).op://
op://VaultName/ItemTitle/field_name
# .env.tpl (commit this file) ANTHROPIC_API_KEY=op://Dev/Anthropic/api_key N8N_API_KEY=op://Dev/n8n/api_key SUPABASE_SERVICE_KEY=op://Dev/Supabase/service_key # ✅ Inject at runtime — secrets stay in subprocess, never in shell history op run --env-file=.env.tpl -- your-command # ⚠️ Avoid sourcing into current shell — unsafe if values contain $(...) or backticks # source <(op run --env-file=.env.tpl -- env) ← skip this pattern
For full syntax and edge cases: references/secret_references.md
Integration Guides
Read references/integrations.md for patterns with:
- Claude Desktop — MCP server config using
op run - n8n — Environment injection at startup, credential push via API
- Docker / Docker Compose —
op run -- docker compose up - GitHub Actions —
1password/load-secrets-action - Python scripts — subprocess + 1Password SDK
- Supabase — Storing and retrieving project credentials
- Replit — Local dev → Replit Secrets bridge
- Rotation workflow — Update in service → update in 1Password → re-inject
Common CLI Commands
Full reference: references/op_commands.md
op item list # List all items op item list --vault Dev # Filter by vault op item get "Item Title" # View item details op item get "Item Title" --format json # JSON output op vault list # List vaults op whoami # Check auth status op account list # List accounts
CI/CD: Service Accounts
For non-interactive environments (GitHub Actions, Docker, n8n server):
export OP_SERVICE_ACCOUNT_TOKEN="ops_eyJ..." op read "op://Dev/MyApp/api_key" # works without signin prompt
Create service accounts: 1Password UI → Settings → Developer → Service Accounts. Grant vault access only to what the service needs.
Security Rules
- Never hardcode secrets — always use
references or runtime injectionop:// - Commit
to private repos only — it exposes vault/item structure, not values.env.tpl - Never commit
(real values) — add it to.env
immediately:.gitignoreecho ".env" >> .gitignore - Use vaults to scope access — separate vault per project or team
- Rotate on exposure — use
then re-inject everywherestore_secret.sh --update - Service accounts for CI/CD — never use personal account tokens in automation