onepassword-cli-coder

SKILL.md

Core Patterns

Secret Reference Format

op://<vault>/<item>/<field>

Examples:

op://Development/AWS/access_key_id
op://Production/Database/password
op://Shared/Stripe/secret_key

Item Naming Conventions

Format: {environment}-{service} with kebab-case. One item per environment.

Pattern Example Bad Alternative
{env}-{service} production-rails Production Rails
{env}-{provider} production-dockerhub API Key
{env}-{provider}-{resource} production-hetzner-s3 Mixed env items

Field Naming

Use semantic field names that describe the credential type:

Good Bad Why
access_token value Self-documenting
master_key secret Specific purpose clear
secret_access_key key Matches AWS naming
api_token token Distinguishes from other tokens

Field naming rules:

  • Match the provider's terminology when possible (AWS uses access_key_id, secret_access_key)
  • Use snake_case for consistency
  • Be specific: database_password not just password when item has multiple credentials

Environment File (.op.env)

Create .op.env in project root:

AWS_ACCESS_KEY_ID=op://Infrastructure/AWS/access_key_id
AWS_SECRET_ACCESS_KEY=op://Infrastructure/AWS/secret_access_key
DIGITALOCEAN_TOKEN=op://Infrastructure/DigitalOcean/api_token
DATABASE_URL=op://Production/PostgreSQL/connection_string
STRIPE_SECRET_KEY=op://Production/Stripe/secret_key

Critical: Add to .gitignore:

# 1Password - NEVER commit
.op.env
*.op.env

Running Commands with Secrets

op run --env-file=.op.env -- terraform plan
op run --env-file=.op.env -- rails server

Integration Patterns

Makefile Integration

OP ?= op
OP_ENV_FILE ?= .op.env

# Prefix for all commands needing secrets
CMD = $(OP) run --env-file=$(OP_ENV_FILE) --

deploy:
	$(CMD) kamal deploy

console:
	$(CMD) rails console

migrate:
	$(CMD) rails db:migrate

Docker Compose

op run --env-file=.op.env -- docker compose up

Kamal Deployment

# config/deploy.yml
env:
  secret:
    - RAILS_MASTER_KEY
    - DATABASE_URL
    - REDIS_URL
# .kamal/secrets
RAILS_MASTER_KEY=$(op read "op://Production/Rails/master_key")
DATABASE_URL=$(op read "op://Production/PostgreSQL/url")
REDIS_URL=$(op read "op://Production/Redis/url")

CI/CD (GitHub Actions)

# .github/workflows/deploy.yml
jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - 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/AWS/access_key_id
          AWS_SECRET_ACCESS_KEY: op://CI/AWS/secret_access_key

      - run: terraform apply -auto-approve

CLI Commands

Reading Secrets

op read "op://Vault/Item/field"
op read "op://Vault/Item/field" --format json
op read "op://Vault/TLS/private_key" > /tmp/key.pem && chmod 600 /tmp/key.pem

Injecting into Commands

DATABASE_URL=$(op read "op://Production/DB/url") rails db:migrate
op run --env-file=.op.env -- ./deploy.sh
op run --account my-team --env-file=.op.env -- terraform apply

Managing Items

op vault list
op item list --vault Infrastructure
op item get "AWS" --vault Infrastructure
op item create --category login --vault Infrastructure \
  --title "New Service" --field username=admin --field password=secret123

Project Setup

Initial Configuration

op signin
op vault list

cat > .op.env << 'EOF'
AWS_ACCESS_KEY_ID=op://Infrastructure/AWS/access_key_id
AWS_SECRET_ACCESS_KEY=op://Infrastructure/AWS/secret_access_key
DATABASE_URL=op://Production/Database/url
REDIS_URL=op://Production/Redis/url
EOF

op run --env-file=.op.env -- env | grep -E '^(AWS|DATABASE|REDIS)'

Placeholder Workflow

Create items with placeholder values upfront, populate with real credentials later:

op item create --vault myproject --category login \
  --title "production-rails" --field master_key="PLACEHOLDER_UPDATE_BEFORE_DEPLOY"

cat > .kamal/secrets << 'EOF'
RAILS_MASTER_KEY=$(op read "op://myproject/production-rails/master_key")
EOF

# Later: update with real value
op item edit "production-rails" --vault myproject \
  master_key="actual_secret_value_here"

Vault Organization

Single-Vault Approach (Simpler)

Use one vault with naming conventions for environment separation:

Vault: myproject
Items:
  - production-rails
  - production-dockerhub
  - production-hetzner-s3
  - staging-rails
  - staging-dockerhub
  - development-rails

Multi-Vault Approach (Team Scale) -- use when teams need different access controls:

Vault Purpose Access
Infrastructure Cloud provider credentials DevOps team
Production Production app secrets Deploy systems
Staging Staging environment Dev team
Development Local dev secrets Individual devs

Security Rules

  • Add .op.env and *.op.env to .gitignore -- never commit
  • Use service accounts for CI/CD, not personal accounts
  • Never pipe op read to logs or echo
  • Never store session tokens in scripts
  • Use variables for vault/item names in automation

Troubleshooting

op signin                  # Re-authenticate expired session
op whoami                  # Check current session
op vault list              # Verify vault access
op item list --vault Infrastructure | grep -i aws   # Search for items
op item get "AWS" --vault Infrastructure --format json | jq '.fields[].label'  # Check field names

Multiple Accounts

Always specify account in automation -- never rely on "last signed in":

op vault list --account acme.1password.com
export OP_ACCOUNT=acme.1password.com
op run --account acme.1password.com --env-file=.op.env -- ./deploy.sh

Multi-Environment Pattern

Use per-environment env files: .op.env.production, .op.env.staging, .op.env.development

ENV ?= development
OP_ENV_FILE = .op.env.$(ENV)

deploy:
	op run --env-file=$(OP_ENV_FILE) -- kamal deploy
# Usage: make deploy ENV=production

References

Weekly Installs
26
GitHub Stars
30
First Seen
Feb 5, 2026
Installed on
opencode26
cursor25
gemini-cli25
github-copilot25
codex25
claude-code24