Skip to content
CLI Tools
Skill

/1password-sdk

How to load secrets and environment variables from 1Password programmatically using the official @1password/sdk (JavaScript/TypeScript). Use this skill whenever code needs to read a 1Password secret, resolve an op:// reference, fetch many secrets at once, discover the

From plugin
claudish
1k3 skills1 command

Claude Code

$ npx -y skills add MadAppGang/claudish --skill 1password-sdk --agent claude-code

SKILL.md

1password-sdk.SKILL.md
name: 1password-sdk
description: >-
  How to load secrets and environment variables from 1Password programmatically
  using the official @1password/sdk (JavaScript/TypeScript). Use this skill
  whenever code needs to read a 1Password secret, resolve an op:// reference,
  fetch many secrets at once, discover the fields/sections of a 1Password item
  (e.g. to import API keys), or read a 1Password Environment — even if the user
  doesn't name the SDK explicitly. Triggers on: "@1password/sdk", "op://",
  "OP_SERVICE_ACCOUNT_TOKEN", "DesktopAuth", "resolve a secret from 1Password",
  "1Password service account", "1Password Environments", "fetch API keys from
  1Password", or wiring 1Password into a Node/Bun/TypeScript app. Prefer this
  in-process SDK over shelling out to the `op` CLI unless the task specifically
  needs the user's interactive `op signin` session.

1Password JavaScript/TypeScript SDK

The official `@1password/sdk` reads secrets from 1Password **in-process** — no `op` CLI subprocess, no `op signin`. It authenticates directly (service-account token or desktop biometric) and resolves `op://vault/item/field` references to their values. Use it whenever an app needs to pull credentials at runtime.

**Why prefer the SDK over the `op` CLI:** one auth model, one authorization event (the CLI + SDK each prompt separately, so mixing them double-prompts), no external binary to depend on, batched resolution, and structured per-reference errors. The CLI's only edge is using a user's existing interactive `op signin` session — the SDK cannot do that; it needs its own auth (below).

Install

bun add @1password/sdk          # or npm install @1password/sdk

For **1Password Environments** (the `environments` API), the stable release does NOT include it — you need the beta:

bun add @1password/sdk@0.4.1-beta.1

Authenticate — create the client once

Every operation goes through a `client`. `integrationName` and `integrationVersion` are **required** (they identify your app in 1Password's audit log — note they do NOT change the desktop authorization prompt, which always shows the calling process).

import { createClient, DesktopAuth } from "@1password/sdk";

// Service account — headless / CI / servers. No prompt, no desktop app.
const client = await createClient({
  auth: process.env.OP_SERVICE_ACCOUNT_TOKEN!,
  integrationName: "my-app",
  integrationVersion: "1.0.0",
});

// OR Desktop app — laptops, biometric (Touch ID). Prompts to authorize.
const client = await createClient({
  auth: new DesktopAuth("my-account-name"), // account name or UUID
  integrationName: "my-app",
  integrationVersion: "1.0.0",
});

**Choosing auth:**

  • `OP_SERVICE_ACCOUNT_TOKEN` → headless, no prompt, but **cannot read Private/Personal

vaults** (shared vaults only). The token is itself a full-decryption secret — never log or persist it.

  • `DesktopAuth` → uses the running desktop app, can read your Private vault, prompts

for Touch ID. Requires the desktop app's SDK integration to be enabled.

`createClient`, and every method below, are **async** — `await` them.

Resolve secrets — the core operation

// One secret:
const apiKey = await client.secrets.resolve("op://Vault/Item/credential");

// Many at once (one round-trip, per-reference errors — prefer this for >1):
const res = await client.secrets.resolveAll([
  "op://Vault/Item/username",
  "op://Vault/Item/password",
]);
for (const [ref, response] of Object.entries(res.individualResponses)) {
  if (response.error) { console.error(`failed ${ref}:`, response.error); continue; }
  console.log(response.content.secret); // the value
}

Keep resolved secrets **in-memory only** — never write them to disk or logs.

→ Full resolution details (reference syntax, OTP/SSH query params, field types, validating a reference, the response shapes): **`references/resolve-secrets.md`**

Read a 1Password Environment (beta)

A named set of env vars managed in the desktop app, addressed by an opaque ID:

const res = await client.environments.getVariables("<environment-id>");
for (const v of res.variables) {
  process.env[v.name] = v.value;   // { name, value, masked }
}

Requires the **beta SDK** and the Environment **ID** (copied from the desktop app: Developer → View Environments → Manage environment → Copy environment ID).

→ Details + the response shape: **`references/environments.md`**

Discover an item's fields (for globbed / bulk imports)

When you want to pull *many* fields from one item — e.g. an item whose fields are each named after an env var (`OPENAI_API_KEY`, `ANTHROPIC_API_KEY`, …) — you must discover them first. `items.get()` takes **IDs, not names**, so the flow is:

// 1. name → vault ID
const vaults = await client.vaults.list();
const vaultId = [...vaults].find(v => v.title === "Jack")!.id;

// 2. name → item ID
const items = await client.items.list(vaultId);
const itemId = items.find(i => i.title === "API keys")!.id;

// 3. fetch the item → fields + sections
const item = await client.items.get(vaultId, itemId);
for (const f of item.fields) {
  // f.title (label), f.sectionId, f.fieldType, f.value
  // join f.sectionId → item.sections[].title for the section label
}

**Note:** `items.get()` returns every field's decrypted `value` — there is no "names without values" mode. This is the same as the `op` CLI's `op item get` (both decrypt in memory; neither writes to disk), so it's not a security regression — just don't persist what you don't use.

→ Full glob/discovery recipe (name→ID resolution, section-label joins, building `op://` references, filtering by a glob): **`references/glob-discovery.md`**

What the SDK can and cannot do

| Need | SDK | Notes | |------|-----|-------| | Resolve `op://` (single + batch) | ✅ | `secrets.resolve` / `resolveAll` | | Validate a reference syntactically | ✅ | `Secrets.validateSecretReference` (static, no network) | | List vaults / items, get it

Read more
@madappgang
Ships withclaudish

Claude Code. Any Model. The most powerful AI coding agent now speaks every language.

Stars on GitHub

Momentum

stars in total
1.0k
Star history of MadAppGang/claudish on GitHub, a chart by star-history.com

Other skills on claudish.

pr-comment

pr-comment

Write GitHub PR comments in Jack's voice. Use whenever writing, drafting, or posting PR comments — review feedback, thank-you…

@madappgang@madappgangInstall Skill
claudish-usage

claudish-usage

CRITICAL - Guide for using Claudish CLI ONLY through sub-agents to run Claude Code with any AI model (OpenRouter, Gemini, OpenAI,…

@madappgang@madappgangInstall Skill

More skills from other plugins.

cli-anything-adguardhome

cli-anything-adguardho…

Command-line interface for AdGuard Home - Network-wide ad blocking and DNS management via AdGuard Home REST API. Designed for AI…

@hkuds@hkudsInstall Skill
find-skills

find-skills

Helps users discover and install agent skills when they ask questions like "how do I do X", "find a skill for X", "is there a…

skills2d39k
@vercel-labs-2@vercel-labs-2Install Skill
ohmyposh

ohmyposh

Install, configure, or troubleshoot Oh My Posh/ohmyposh: shell init, themes, segments, Nerd Font icons, and prompt setup on…

@jandedobbeleer@jandedobbeleerInstall Skill

Questions about 1password-sdk.

Which coding agents can use 1password-sdk?
1password-sdk installs in Claude Code, Codex, Cursor, Gemini CLI, GitHub Copilot, OpenCode and Windsurf with the skills CLI, using each agent's flag shown on this page. Flowy's auto-invocation, which fires a skill when your prompt matches, runs in Claude Code only.