npx skills add ...
npx skills add julianobarbosa/claude-code-skills --skill 1password
Guide for implementing 1Password secrets management - CLI operations, service accounts, Developer Environments, and Kubernetes integration. Use when retrieving secrets, managing vaults, configuring CI/CD pipelines, integrating with External Secrets Operator, managing Developer Environments, or automating secrets workflows with 1Password.
npx skills add julianobarbosa/claude-code-skills --skill 1password
This skill provides comprehensive guidance for working with 1Password's secrets management ecosystem. It covers the op CLI for local development, service accounts for automation, Developer Environments for project secrets, and Kubernetes integrations including the native 1Password Operator and External Secrets Operator.
1Password CLI uses a noun-verb structure: op <noun> <verb> [flags]
Developer Environments provide a dedicated location to store, organize, and manage project secrets as environment variables. CLI tools are available in both TypeScript/Bun and Python SDK variants.
| Feature | GUI | TypeScript CLI | Python SDK CLI |
|---|---|---|---|
| Create environment | Yes | bun run create | uv run op-env-create |
| Update environment | Yes | bun run update | uv run op-env-update |
| Delete environment | Yes | bun run delete | uv run op-env-delete |
| Show environment | Yes | bun run show | uv run op-env-show |
| List environments | Yes | bun run list | uv run op-env-list |
| Export to .env | Yes | bun run export | uv run op-env-export |
| Mount .env file | Yes (beta) | No | No |
Tools are written in TypeScript and require Bun runtime:
Python tools use the official onepassword-sdk package and require uv:
Requirements: Python 3.9+, OP_SERVICE_ACCOUNT_TOKEN environment variable.
| Use Case | Recommended | Why |
|---|---|---|
| Python applications (FastAPI, Django) | Python SDK | Native async, no subprocess overhead |
| Shell scripts, CI/CD pipelines | TypeScript CLI or op CLI | Direct CLI integration |
| Batch secret resolution | Python SDK | resolve_all() for efficiency |
| Tag-based filtering | TypeScript CLI | SDK lacks tag filter support |
| Interactive local development | Either | Both have identical interfaces |
For Python applications that need runtime secret resolution:
See references/python-sdk.md for full SDK reference and integration patterns.
Access individual variables using the secret reference format:
Example:
Name each 1Password Developer Environment after the thing it holds credentials for, e.g.
<project>-azure-rg-<name>-dev, <team>-pim, <project>-github. Keep the actual inventory of your
environments in a git-ignored local note, not in a committed (and potentially public) skill file.
The standard format for referencing secrets:
Examples:
op://Development/AWS/access_key_idop://Production/Database/passwordop://Shared/API Keys/github_tokenThe op run command injects secrets as environment variables:
The op inject command replaces secret references in template files:
Service accounts enable automation without personal credentials.
Via CLI:
Export the service account token:
Then use normal CLI commands - they automatically authenticate with the service account.
External Secrets Operator (ESO) syncs secrets from 1Password to Kubernetes.
1password-credentials.json)Basic secret retrieval:
Using dataFrom with regex:
The native 1Password Operator provides direct integration without External Secrets Operator.
This creates a Kubernetes Secret named database-secret with all fields from the 1Password item.
Enable automatic deployment restarts when secrets change:
Shell plugins enable automatic authentication for third-party CLIs.
Use 1Password to manage GitHub authentication for git operations (push, pull, clone).
Run the setup script to configure everything:
Add to your ~/.zshrc or ~/.bashrc:
If you work with multiple GitHub accounts, you can configure per-repo credentials:
This means the 1Password plugin is pointing to a deleted token:
If gh is aliased to run through 1Password but failing:
Verify the credential helper is configured:
Should show:
Authentication fails:
Item not found:
Permission denied in CI/CD:
External Secrets not syncing:
op://) instead of hardcoding vault/item names in scriptsreferences/cli-commands.md - Complete CLI command referencereferences/kubernetes-examples.md - Kubernetes manifest examplesreferences/python-sdk.md - Python SDK reference and integration guidereferences/environments/README.md - Developer Environments guideEnvironment management CLI tools in TypeScript and Python:
| Operation | TypeScript (tools/) | Python (tools-python/) |
|---|---|---|
| Create | bun run create | uv run op-env-create |
| Update | bun run update | uv run op-env-update |
| Delete | bun run delete | uv run op-env-delete |
| Show | bun run show | uv run op-env-show |
| List | bun run list | uv run op-env-list |
| Export | bun run export | uv run op-env-export |
TypeScript requirements: Bun runtime
Python requirements: Python 3.9+, uv, OP_SERVICE_ACCOUNT_TOKEN
Environment and integration templates (in templates/):
| Template | Description |
|---|---|
env.template | Standard .env file template |
env-op-refs.template | Template with op:// references |
github-actions-env.yaml | GitHub Actions workflow example |
docker-compose-env.yaml | Docker Compose with secrets injection |
scripts/setup-gh-plugin.sh - Setup GitHub CLI with 1Password integrationscripts/setup-service-account.sh - Create and configure a service accountscripts/sync-check.sh - Verify External Secrets synchronizationop interactively won't necessarily work as a service-account token.op inject evaluates op://... refs at render time — templates checked into git are safe; rendered output never goes near git.OP_DEVICE is set — CI containers without that env var fail silently as if there were no secrets.op plugin init) sources at shell start — plugin updates don't apply until you open a new shell.op read op://vault/item/field returns the FIRST match across duplicates — items with the same field name resolve by lexicographic order, not creation date.What do you need to do?
├── Retrieve a secret for local development?
│ └── Use: op read, op run, or op inject
├── Manage project environment variables?
│ └── See: Developer Environments (below)
├── Manage items/vaults in 1Password?
│ └── Use: op item, op vault, op document commands
├── Automate secrets in CI/CD?
│ └── Use: Service Accounts with OP_SERVICE_ACCOUNT_TOKEN
├── Sync secrets to Kubernetes?
│ ├── Using External Secrets Operator?
│ │ └── See: External Secrets Operator Integration
│ └── Using native 1Password Operator?
│ └── See: 1Password Kubernetes Operator
└── Configure shell plugins for CLI tools?
└── Use: op plugin commands# Navigate to tools directory
cd tools
# Run any tool with bun
bun run src/op-env-create.ts --help
bun run src/op-env-list.ts --help
# Or use npm scripts
bun run create -- --help
bun run list -- --help# Navigate to tools-python directory
cd tools-python
# Install dependencies
uv sync
# Run any tool
uv run op-env-create --help
uv run op-env-list --helpfrom op_env.secrets_manager import SecretsManager
async def main():
sm = await SecretsManager.create()
# Single secret (with caching)
api_key = await sm.get("op://Production/API/key")
# Batch resolve
secrets = await sm.get_many([
"op://Production/DB/password",
"op://Production/DB/host",
])
# Load all vars from an environment item
env = await sm.resolve_environment("my-app-prod", "Production")# From inline variables
bun run src/op-env-create.ts my-app-dev Personal \
API_KEY=secret \
DB_HOST=localhost \
DB_PORT=5432
# From .env file
bun run src/op-env-create.ts my-app-prod Production --from-file .env.prod
# Combine file + inline (inline overrides file)
bun run src/op-env-create.ts azure-config Shared --from-file .env EXTRA_KEY=value
# With custom tags
bun run src/op-env-create.ts secrets DevOps --tags "env,production,api" KEY=value# List all environments (tagged with 'environment')
bun run src/op-env-list.ts
# Filter by vault
bun run src/op-env-list.ts --vault Personal
# Filter by tags
bun run src/op-env-list.ts --tags "production"
# JSON output
bun run src/op-env-list.ts --json# Show with masked values (default)
bun run src/op-env-show.ts my-app-dev Personal
# Show with revealed values
bun run src/op-env-show.ts my-app-dev Personal --reveal
# JSON output
bun run src/op-env-show.ts my-app-dev Personal --json
# Show only variable names
bun run src/op-env-show.ts my-app-dev Personal --keys# Update/add single variable
bun run src/op-env-update.ts my-app-dev Personal API_KEY=new-key
# Merge from .env file
bun run src/op-env-update.ts my-app-dev Personal --from-file .env.local
# Remove variables
bun run src/op-env-update.ts my-app-dev Personal --remove OLD_KEY,DEPRECATED
# Update and remove in one command
bun run src/op-env-update.ts my-app-dev Personal NEW_KEY=value --remove OLD_KEY# Export to .env file (standard format)
bun run src/op-env-export.ts my-app-dev Personal > .env
# Docker-compatible format (quoted values)
bun run src/op-env-export.ts my-app-dev Personal --format docker > .env
# op:// references template (for op run/inject)
bun run src/op-env-export.ts my-app-dev Personal --format op-refs > .env.tpl
# JSON format
bun run src/op-env-export.ts my-app-dev Personal --format json
# Add prefix to all variables
bun run src/op-env-export.ts azure-config Shared --prefix AZURE_ > .env# Interactive deletion (asks for confirmation)
bun run src/op-env-delete.ts my-app-dev Personal
# Force delete without confirmation
bun run src/op-env-delete.ts my-app-dev Personal --force
# Archive instead of permanent delete
bun run src/op-env-delete.ts my-app-dev Personal --archiveop://<vault>/<environment>/variables/<key># Read single variable
op read "op://Personal/my-app-dev/variables/API_KEY"
# Use in template file (.env.tpl)
API_KEY=op://Personal/my-app-dev/variables/API_KEY
DB_HOST=op://Personal/my-app-dev/variables/DB_HOST# 1. Export environment as op:// template
bun run src/op-env-export.ts my-app-dev Personal --format op-refs > .env.tpl
# 2. Run command with injected secrets
op run --env-file .env.tpl -- ./deploy.sh
op run --env-file .env.tpl -- docker compose up
op run --env-file .env.tpl -- npm start
op run --env-file .env.tpl -- python app.py# 1. Create template with op:// references
bun run src/op-env-export.ts my-app-dev Personal --format op-refs > config.tpl
# 2. Inject secrets into file
op inject -i config.tpl -o .env
# 3. Use the generated .env file
source .env && ./app# 1. Export environment
bun run src/op-env-export.ts my-app-dev Personal --format op-refs > .env.tpl
# 2. Run docker compose with secrets
op run --env-file .env.tpl -- docker compose up -dname: Deploy
on: [push]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install 1Password CLI
uses: 1password/install-cli-action@v1
- name: Load secrets
uses: 1password/load-secrets-action@v2
with:
export-env: true
env:
OP_SERVICE_ACCOUNT_TOKEN: ${{ secrets.OP_SERVICE_ACCOUNT_TOKEN }}
API_KEY: op://CI-CD/my-app-prod/variables/API_KEY
DB_PASSWORD: op://CI-CD/my-app-prod/variables/DB_PASSWORD
- name: Deploy
run: ./deploy.shop://<vault>/<item>/<field># Read a specific field
op read "op://Development/AWS/access_key_id"
# Read with JSON output
op item get "AWS" --vault Development --format json
# Read specific field from item
op item get "AWS" --vault Development --fields access_key_id# Run command with secrets
op run --env-file=.env.tpl -- ./deploy.sh
# Example .env.tpl file:
# AWS_ACCESS_KEY_ID=op://Development/AWS/access_key_id
# AWS_SECRET_ACCESS_KEY=op://Development/AWS/secret_access_key# Inject secrets from template to output file
op inject -i config.tpl.yaml -o config.yaml
# Example config.tpl.yaml:
# database:
# host: localhost
# password: op://Production/Database/password# Create a login item
op item create --category login \
--title "My Service" \
--vault Development \
username=admin \
password=secretpassword
# Create with generated password
op item create --category login \
--title "New Account" \
--generate-password
# Create from JSON template
op item create --template item.json{
"title": "my-service-credentials",
"vault": {"id": "vault-uuid-or-name"},
"category": "LOGIN",
"fields": [
{"label": "username", "value": "admin", "type": "STRING"},
{"label": "password", "value": "secret", "type": "CONCEALED"},
{"label": "api_key", "value": "key123", "type": "CONCEALED"}
]
}# Edit a field
op item edit "My Service" password=newpassword
# Add a new field
op item edit "My Service" api_key=newkey
# Edit with specific vault
op item edit "My Service" --vault Development password=newpassword# Create with read-only access
op service-account create "CI/CD Pipeline" \
--vault Production:read_items
# Create with write access
op service-account create "Deployment Bot" \
--vault Production:read_items,write_items
# Create with vault creation permission
op service-account create "Provisioning Bot" \
--vault Production:read_items,write_items \
--can-create-vaultsexport OP_SERVICE_ACCOUNT_TOKEN="ops_..."name: Deploy
on: [push]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install 1Password CLI
uses: 1password/install-cli-action@v1
- name: Load secrets
uses: 1password/load-secrets-action@v2
with:
export-env: true
env:
OP_SERVICE_ACCOUNT_TOKEN: ${{ secrets.OP_SERVICE_ACCOUNT_TOKEN }}
AWS_ACCESS_KEY_ID: op://CI-CD/AWS/access_key_id
AWS_SECRET_ACCESS_KEY: op://CI-CD/AWS/secret_access_key
- name: Deploy
run: ./deploy.shdeploy:
image: 1password/op:2
variables:
OP_SERVICE_ACCOUNT_TOKEN: $OP_SERVICE_ACCOUNT_TOKEN
script:
- export AWS_ACCESS_KEY_ID=$(op read "op://CI-CD/AWS/access_key_id")
- export AWS_SECRET_ACCESS_KEY=$(op read "op://CI-CD/AWS/secret_access_key")
- ./deploy.shversion: 2.1
orbs:
onepassword: onepassword/secrets@1
jobs:
deploy:
docker:
- image: cimg/base:stable
steps:
- checkout
- onepassword/exec:
command: ./deploy.sh
env:
AWS_ACCESS_KEY_ID: op://CI-CD/AWS/access_key_id
AWS_SECRET_ACCESS_KEY: op://CI-CD/AWS/secret_access_key# Create automation environment and get credentials
# This generates 1password-credentials.json and an access token
# Create Kubernetes secret for Connect Server credentials
kubectl create secret generic onepassword-credentials \
--from-file=1password-credentials.json
# Create secret for access token
kubectl create secret generic onepassword-token \
--from-literal=token=your-access-tokenapiVersion: apps/v1
kind: Deployment
metadata:
name: onepassword-connect
spec:
replicas: 1
selector:
matchLabels:
app: onepassword-connect
template:
metadata:
labels:
app: onepassword-connect
spec:
containers:
- name: connect-api
image: 1password/connect-api:latest
ports:
- containerPort: 8080
volumeMounts:
- name: credentials
mountPath: /home/opuser/.op/1password-credentials.json
subPath: 1password-credentials.json
volumes:
- name: credentials
secret:
secretName: onepassword-credentials
---
apiVersion: v1
kind: Service
metadata:
name: onepassword-connect
spec:
selector:
app: onepassword-connect
ports:
- port: 8080
targetPort: 8080apiVersion: external-secrets.io/v1
kind: ClusterSecretStore
metadata:
name: onepassword
spec:
provider:
onepassword:
connectHost: http://onepassword-connect:8080
vaults:
production: 1
staging: 2
auth:
secretRef:
connectTokenSecretRef:
name: onepassword-token
namespace: external-secrets
key: tokenapiVersion: external-secrets.io/v1
kind: ExternalSecret
metadata:
name: database-credentials
spec:
refreshInterval: 1h
secretStoreRef:
kind: ClusterSecretStore
name: onepassword
target:
name: database-credentials
creationPolicy: Owner
data:
- secretKey: username
remoteRef:
key: Database # Item title in 1Password
property: username # Field label
- secretKey: password
remoteRef:
key: Database
property: passwordapiVersion: external-secrets.io/v1
kind: ExternalSecret
metadata:
name: env-config
spec:
refreshInterval: 1h
secretStoreRef:
kind: ClusterSecretStore
name: onepassword
target:
name: app-env
dataFrom:
- find:
path: app-config # Item title
name:
regexp: "^[A-Z_]+$" # Match all uppercase env varsapiVersion: external-secrets.io/v1alpha1
kind: PushSecret
metadata:
name: push-generated-secret
spec:
refreshInterval: 1h
secretStoreRefs:
- name: onepassword
kind: ClusterSecretStore
selector:
secret:
name: generated-credentials
data:
- match:
secretKey: api-key
remoteRef:
remoteKey: generated-api-key
property: password
metadata:
apiVersion: kubernetes.external-secrets.io/v1alpha1
kind: PushSecretMetadata
spec:
vault: production
tags:
- generated
- kuberneteshelm repo add 1password https://1password.github.io/connect-helm-charts
helm install connect 1password/connect \
--set-file connect.credentials=1password-credentials.json \
--set operator.create=true \
--set operator.token.value=your-access-tokenapiVersion: onepassword.com/v1
kind: OnePasswordItem
metadata:
name: database-secret
spec:
itemPath: "vaults/Production/items/Database"# Operator-level (environment variable)
AUTO_RESTART=true
# Namespace-level (annotation)
apiVersion: v1
kind: Namespace
metadata:
name: production
annotations:
operator.1password.io/auto-restart: "true"
# Deployment-level (annotation)
apiVersion: apps/v1
kind: Deployment
metadata:
annotations:
operator.1password.io/auto-restart: "true"# List available plugins
op plugin list
# Common plugins: aws, gh, stripe, vercel, fly, etc.# Initialize AWS plugin
op plugin init aws
# This configures shell aliases to use 1Password for AWS credentials
# Add to your shell profile as instructed./scripts/setup-gh-plugin.sh# Sign in to 1Password
op signin
# Initialize gh plugin (interactive - select your GitHub token)
op plugin init gh# Remove any broken credential helpers
git config --global --unset-all credential.https://github.com.helper 2>/dev/null
# Set gh as the credential helper for GitHub
git config --global credential.https://github.com.helper '!/opt/homebrew/bin/gh auth git-credential'
git config --global credential.https://gist.github.com.helper '!/opt/homebrew/bin/gh auth git-credential'# 1Password CLI plugins
source ~/.config/op/plugins.sh┌─────────────────────────────────────────────────────────────────┐
│ Git Push Workflow │
├─────────────────────────────────────────────────────────────────┤
│ │
│ git push │
│ │ │
│ ▼ │
│ Git credential helper │
│ │ │
│ ▼ │
│ gh auth git-credential │
│ │ │
│ ▼ │
│ 1Password plugin (via op wrapper) │
│ │ │
│ ▼ │
│ 1Password (biometric/password unlock) │
│ │ │
│ ▼ │
│ Token retrieved and passed to git │
│ │ │
│ ▼ │
│ Push completes successfully │
│ │
└─────────────────────────────────────────────────────────────────┘# For a specific repo, use a different 1Password item
cd /path/to/work-repo
git config credential.https://github.com.helper '!/opt/homebrew/bin/gh auth git-credential'
# Or use includeIf in ~/.gitconfig for path-based selection
[includeIf "gitdir:~/work/"]
path = ~/.gitconfig-work# Remove the broken plugin configuration
rm ~/.config/op/plugins/used_items/gh.json
# Re-initialize
op plugin init gh# Check the alias
which gh # Shows: gh: aliased to op plugin run -- gh
# Run gh directly to bypass the alias
/opt/homebrew/bin/gh auth statusgit config --list | grep credentialcredential.https://github.com.helper=!/opt/homebrew/bin/gh auth git-credential# Check current session
op whoami
# Sign in again
op signin
# For service accounts, verify token
echo $OP_SERVICE_ACCOUNT_TOKEN | head -c 10# List items in vault to verify name
op item list --vault "Vault Name"
# Use item ID instead of name for reliability
op item get --vault Development dh7fjsh3kd8fjs# Verify service account has access to vault
op vault list # Should show accessible vaults
# Check rate limits
op service-account ratelimit# Check ExternalSecret status
kubectl describe externalsecret <name>
# Check Connect Server logs
kubectl logs -l app=onepassword-connect
# Verify SecretStore connection
kubectl describe secretstore <name># TypeScript tools
cd tools && bun run src/op-env-list.ts --help
# Python SDK tools
cd tools-python && uv sync && uv run op-env-list --help