home / skills / 0xbigboss / claude-code / op-cli

op-cli skill

/.claude/skills/op-cli

This skill helps securely read 1Password secrets, discover vaults and items, and pipe credentials to tools without exposing sensitive values.

npx playbooks add skill 0xbigboss/claude-code --skill op-cli

Review the files below or copy the command above to add this skill to your agents.

Files (1)
SKILL.md
3.8 KB
---
name: op-cli
description: Secure 1Password CLI patterns for reading secrets, discovering vaults/items, and piping credentials to other tools. Use when reading from 1Password, rotating secrets, or piping credentials to wrangler/kubectl/etc. Triggers on op CLI, 1Password, secret rotation, or credential piping tasks.
---

# 1Password CLI (`op`) — Secure Handling

## Core Rule: Never Print Secrets

**NEVER** use `op` commands that would print secret values into the conversation. Always pipe directly to the consuming tool or use `wc -c` / redaction to verify without exposing.

```bash
# WRONG — would print secret to stdout (do not run)
# op item get ITEM_ID --vault VAULT --fields label=PASSWORD --reveal

# RIGHT — pipe directly to consumer
op item get ITEM_ID --vault VAULT --fields label=PASSWORD --reveal | \
  wrangler secret put SECRET_NAME --env ENV

# RIGHT — verify a value exists without exposing it
op item get ITEM_ID --vault VAULT --fields label=PASSWORD --reveal 2>/dev/null | wc -c
```

## Item Titles with Slashes

Many 1Password items use path-style titles (e.g. `pool-party/testnet-pool-party-public/credentials`). The `op://` URI format **breaks** with these because it uses `/` as a delimiter.

```bash
# BROKEN — too many '/' segments
op read "op://pool-party-testnet/pool-party/testnet-pool-party-public/credentials/PASSWORD"
# ERROR: too many '/': secret references should match op://<vault>/<item>[/<section>]/<field>

# WORKS — use item ID instead (avoid printing values)
op item get ITEM_ID --vault VAULT --fields label=FIELD --reveal 2>/dev/null | wc -c
```

### Discovery Workflow

When you don't know the item ID:

```bash
# 1. List items in a vault to find the title and ID
op item list --vault VAULT_NAME

# 2. Use the ID (first column) for all subsequent reads
op item get ITEM_ID --vault VAULT_NAME --fields label=FIELD_NAME --reveal 2>/dev/null | wc -c
```

## Reading Multiple Fields from One Item

```bash
# Verify which fields exist (safe — shows labels not values)
op item get ITEM_ID --vault VAULT_NAME --format json 2>/dev/null | \
  python3 -c "import json,sys; [print(f['label']) for s in json.load(sys.stdin).get('fields',[]) for f in [s] if f.get('label')]"

# Pipe each field to its destination
op item get ITEM_ID --vault VAULT --fields label=USERNAME --reveal | consumer_cmd ...
op item get ITEM_ID --vault VAULT --fields label=PASSWORD --reveal | consumer_cmd ...
```

## Common Piping Patterns

### Cloudflare Workers (wrangler)
```bash
op item get ITEM_ID --vault VAULT --fields label=PASSWORD --reveal | \
  npx wrangler secret put POOL_PARTY_PUBLIC_PASSWORD --env testnet
```

### Environment Variable (subshell)
```bash
SECRET="$(op item get ITEM_ID --vault VAULT --fields label=TOKEN --reveal 2>/dev/null)"
# Use $SECRET in subsequent commands within the same shell — it won't appear in output
```

### kubectl
```bash
op item get ITEM_ID --vault VAULT --fields label=PASSWORD --reveal | \
  kubectl create secret generic my-secret --from-file=password=/dev/stdin
```

## Verification Without Exposure

```bash
# Check a value is non-empty (char count)
op item get ITEM_ID --vault VAULT --fields label=PASSWORD --reveal 2>/dev/null | wc -c

# Compare two sources match (exit code only)
if cmp -s <(op item get ID1 --vault V --fields label=F --reveal 2>/dev/null) \
        <(op item get ID2 --vault V --fields label=F --reveal 2>/dev/null); then
  echo "match"
else
  echo "differ"
fi
```

## Troubleshooting

| Error | Cause | Fix |
|---|---|---|
| `too many '/'` | Item title has slashes, `op://` can't parse it | Use item ID with `op item get` |
| `could not find item` | Wrong vault or title mismatch | Run `op item list --vault VAULT` to discover |
| Empty output | Missing `--reveal` flag | Add `--reveal` and pipe to consumer (or `| wc -c`) |
| `not signed in` | Session expired | Run `eval "$(op signin)"` (avoid printing the session token) |

Overview

This skill provides secure 1Password CLI (op) patterns for reading secrets, discovering vaults and items, and piping credentials to other tools without exposing secret values. It focuses on safe retrieval, discovery workflows, piping into consumers (wrangler, kubectl, subshells), and verification techniques that avoid printing secrets to stdout. Use it to integrate 1Password into automation while maintaining secrecy and auditability.

How this skill works

The skill teaches using op item get with item IDs and vaults, piping revealed values directly into consuming commands, and using safe verification commands like wc -c or cmp that only return exit status or counts. It shows discovery steps for finding item IDs, handling item titles that contain slashes (which break op:// URIs), and common piping patterns for wrangler, kubectl, and environment-variable use in subshells. Troubleshooting entries map common op errors to concrete fixes.

When to use it

  • Reading secrets from 1Password for deployment or automation without exposing values.
  • Rotating credentials and piping new secrets into service CLIs (wrangler, kubectl, etc.).
  • Discovering vault items when you only know a path-like title or need an item ID.
  • Verifying secret presence or equality without printing secret contents.
  • Scripting CI/CD tasks that consume 1Password secrets securely.

Best practices

  • Never print secret values in logs or terminal output; always pipe directly to the consumer.
  • Prefer item IDs over op:// URIs when titles include slashes to avoid parsing errors.
  • Use 2>/dev/null and wc -c or cmp to verify values without revealing them.
  • Keep sessions fresh with eval "$(op signin)" but never echo or log the session token.
  • Limit visibility by piping to stdin (e.g., kubectl --from-file=/dev/stdin) instead of writing files.

Example use cases

  • Pipe a password into Cloudflare Workers: op item get ITEM_ID --vault VAULT --fields label=PASSWORD --reveal | npx wrangler secret put NAME --env ENV
  • Load a token into a subshell variable without printing: SECRET="$(op item get ITEM_ID --vault VAULT --fields label=TOKEN --reveal 2>/dev/null)"
  • Discover an item ID when you only know the vault: op item list --vault VAULT_NAME then use the ID with op item get
  • Check a secret is non-empty using character count: op item get ITEM_ID --vault VAULT --fields label=PASSWORD --reveal 2>/dev/null | wc -c

FAQ

What causes the 'too many "/"' error and how do I fix it?

Item titles that include slashes break the op:// URI parser. Use the item ID with op item get and specify --vault instead of op:// paths.

How can I verify a secret exists without exposing it?

Pipe the revealed value to wc -c to check character count or use cmp -s on process substitutions to compare values; both avoid printing the secret.