agentsclimarketplace

Op secrets injection

Skill RadOrigin-LLC/RAD-Claude-Skills/plugins/rad-1password/skills/op-secrets-injection

Use this skill when the user is loading 1Password secrets into a running process or config file — anything involving `op run`, `op inject`, `op read`, `.env` files containing `op://...` references, secret-reference template syntax, the `{{ op://... }}` placeholder format, populating YAML/JSON/TOML config from a template, or wiring 1Password into Docker/Kubernetes/CI/CD. Also use when the user asks how to keep secrets out of `.env`, source control, or shell history.From its SKILL.md

Install
npx -y skills add RadOrigin-LLC/RAD-Claude-Skills --skill op-secrets-injection

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 5 stars5 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

SKILL.md

7.7 KB, ~2.0k tokens by cl100k_base, as published. Nobody here has run it

Loading secrets at runtime: op read, op inject, op run

Three commands solve three different problems. Pick by destination, not by habit.

DestinationUse
Single secret value, transient (one shell command)op read
Config file on disk (or stdin/stdout pipeline) with placeholdersop inject
Process that expects env vars (most apps, dev servers, scripts)op run

op read — single secret to stdout

op read [flags] <secret-reference>
FlagPurpose
-o, --out-file <path>Write to file instead of stdout.
--file-mode <octal>Output file mode (default 0600).
-n, --no-newlineSuppress trailing newline.
-f, --forceOverwrite existing file without prompt.

Reference query parameters

Append ?attribute=... or ?ssh-format=... to extract derived values:

op read "op://prod/2fa/otp-field?attribute=otp"            # current 6-digit code
op read "op://prod/login/password?attribute=type"          # field type metadata
op read "op://prod/ssh-key/private key?ssh-format=openssh" # OpenSSH-formatted key

Inline in commands

This is fine when the secret is needed once and won't end up in ps output for long:

docker login -u "$(op read op://prod/docker/user)" -p "$(op read op://prod/docker/pass)"
psql "$(op read op://prod/db/connection_string)"

For long-running commands, prefer op run — exposing secrets via $(...) puts them in the parent shell's argv briefly.

op inject — render a templated file

op inject [flags]
FlagPurpose
-i, --in-file <path>Template input. If omitted, reads stdin.
-o, --out-file <path>Output destination. If omitted, writes stdout.
--file-mode <octal>Output file mode (default 0600).
-f, --forceOverwrite existing output.

Template syntax

Two reference forms are accepted in templates:

unenclosed:   op://vault/item/field
enclosed:     {{ op://vault/item/field }}

Use enclosed in nearly every case — they're robust around adjacent text:

database_url: postgres://{{ op://prod/db/user }}:{{ op://prod/db/pass }}@{{ op://prod/db/host }}/{{ op://prod/db/name }}

Unenclosed references end at the first character outside [A-Za-z0-9_.?\-], which makes adjacent characters dangerous.

Environment-variable interpolation in templates

Templates can also expand env vars, with default-value support:

${VAR}            ${VAR:-default}
$VAR              op://${ENV:-dev}/db/password

Combined: a single template handles dev/staging/prod by exporting ENV differently before each op inject.

Streaming when you don't need the file on disk

op inject -i nginx.conf.tpl | docker run -i --rm nginx nginx -c /dev/stdin -t
op inject -i app.yaml.tpl | kubectl apply -f -

This avoids the "delete the resolved file when done" rule entirely.

When you must write the file

Always treat output as plaintext-secret material:

op inject -i config.yml.tpl -o config.yml
trap 'shred -u config.yml 2>/dev/null || rm -f config.yml' EXIT
# ... start app that reads config.yml ...

Add the resolved filename to .gitignore.

op run — exec a command with secrets in env

op run [flags] -- <command> [args...]
FlagPurpose
--env-file <path>Load env vars from a dotenv file. Repeatable; later files win on conflict.
--no-maskingDon't redact secrets in the subprocess's stdout/stderr.

The dotenv pattern (recommended for app dev)

.env contains references, not values. Commit it. The plaintext secrets never touch disk:

# .env — safe to commit
DATABASE_URL=op://prod/db/connection_string
STRIPE_SECRET_KEY=op://prod/stripe/api-key
JWT_SIGNING_KEY=op://prod/auth/jwt-key
SENTRY_DSN=op://prod/sentry/dsn
op run --env-file=.env -- npm run dev
op run --env-file=.env -- python manage.py runserver
op run --env-file=.env -- ./bin/server

Multi-environment with one template

.env references a variable substituted at run time:

# .env
DATABASE_URL=op://${APP_ENV}/db/connection_string
API_KEY=op://${APP_ENV}/api/key
APP_ENV=staging op run --env-file=.env -- ./bin/server
APP_ENV=prod    op run --env-file=.env -- ./bin/server

Chained references (env var → secret reference)

Set the env var to a reference, then use a subshell so $VAR expands inside the subprocess (after op run has substituted):

DB_PASS=op://prod/db/password op run -- sh -c 'echo "$DB_PASS" | psql ...'

The wrong way (broken):

DB_PASS=op://prod/db/password op run -- echo "$DB_PASS"
# parent shell expands $DB_PASS to the literal "op://..." string before op run sees it

Masking

By default, secrets passed via env are redacted from the child process's stdout/stderr. Helpful for screenshare/CI logs. Disable with --no-masking (or OP_RUN_NO_MASKING=true) only for debugging.

Multiple env files

op run --env-file=.env.shared --env-file=.env.local -- ./bin/server

Later files override earlier files for the same key.

CI / production patterns

GitHub Actions

- uses: 1password/load-secrets-action@v2
  with:
    export-env: true
  env:
    OP_SERVICE_ACCOUNT_TOKEN: ${{ secrets.OP_SERVICE_ACCOUNT_TOKEN }}
    DATABASE_URL: op://prod/db/connection_string
    STRIPE_KEY: op://prod/stripe/api-key
- run: ./bin/migrate && ./bin/start

If you don't want the Action, raw op works:

- run: |
    curl -sSf https://downloads.1password.com/linux/keys/1password.asc | sudo gpg --dearmor -o /usr/share/keyrings/1password-archive-keyring.gpg
    echo "deb [signed-by=/usr/share/keyrings/1password-archive-keyring.gpg] https://downloads.1password.com/linux/debian/$(dpkg --print-architecture) stable main" | sudo tee /etc/apt/sources.list.d/1password.sources
    sudo apt update && sudo apt install -y 1password-cli
    op run --env-file=.env -- ./bin/migrate
  env:
    OP_SERVICE_ACCOUNT_TOKEN: ${{ secrets.OP_SERVICE_ACCOUNT_TOKEN }}

Docker (build vs run)

Don't bake secrets into images. Inject at run time:

docker run --rm \
  -e OP_SERVICE_ACCOUNT_TOKEN \
  -v "$PWD/.env:/app/.env:ro" \
  -v "$(which op):/usr/local/bin/op:ro" \
  myapp:latest \
  op run --env-file=/app/.env -- /app/bin/start

Better: use the official 1password/op image multi-stage to bake op into your runtime image, then run as above.

Kubernetes

Use the 1Password Operator or render Secret manifests with op inject at deploy time:

op inject -i secret.yaml.tpl | kubectl apply -f -

Anti-patterns to flag

  • A .env file with plaintext values committed to a repo. Replace values with op://... references and run via op run --env-file.
  • op read $REF >> ~/.bashrc. Bakes the value into the dotfile. Use op run or read on demand.
  • A script that does export PASS=$(op read ...) then runs many subcommands. Acceptable for ad-hoc use; for anything checked in, prefer op run --env-file=.env -- script.sh.
  • Calling op read in a hot loop. Each call hits the local agent / 1Password.com. Read once into a variable, or run the inner work under op run.
  • Using --no-masking in production. It's a debug flag.

What ships with it

Read from the repository

Just SKILL.md. No reference files, no scripts.

Gives 0 of the 12 instructions most containers cloud skills give in ~2.0k tokens

Counted across 607 of the 657 authors here whose files we hold, read 2026-08-07

  • Run containers as a non-root userin 66 of 607, across 46 files
  • Use multi-stage buildsin 53 of 607, across 44 files
  • Use Promise.all for independent operationsin 47 of 607, across 13 files
  • Import directly instead of barrel filesin 46 of 607, across 12 files
  • Use ternary instead of AND for conditionalsin 45 of 607, across 12 files
  • Use Set or Map for O(1) lookupsin 42 of 607, across 10 files
  • Create a .dockerignore filein 41 of 607, across 31 files
  • Read individual rule files for detailsin 39 of 607, across 9 files
  • Copy dependency files before source codein 36 of 607, across 23 files
  • Authenticate server actions like API routesin 35 of 607, across 7 files
  • Use next/dynamic for heavy componentsin 34 of 607, across 9 files
  • Use React.cache for per-request deduplicationin 34 of 607, across 10 files

Said here and by no other author read

  • pick the command by destination type
  • use op read for single transient values
  • use op inject for templated files
  • use op run for processes needing env vars
  • use enclosed template references in op inject
  • stream templated output to avoid disk writes

Grouped from the skills themselves: near-identical wordings counted once, and counted by distinct author, so one author publishing three of these counts once. Length counted with cl100k_base; the agent that loads this file may tokenize it differently.

Keep looking

Skills are one crate of 326,871. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.